Skip to content

Commit

Permalink
com.unity.mobile.notifications@1.4.2
Browse files Browse the repository at this point in the history
## [1.4.2] - 2021-07-22

### Fixes:
- [Android] [issue 99](Unity-Technologies/com.unity.mobile.notifications#99) Use FLAG_IMMUTABLE for PendingIntent
- [iOS] Do not touch Plist file unless modifications are required
- [iOS] [1348518](https://issuetracker.unity3d.com/product/unity/issues/guid/1348518) Fix crash in push notification (case )
  • Loading branch information
Unity Technologies committed Jul 22, 2021
1 parent 9bda3f0 commit 8b0c223
Show file tree
Hide file tree
Showing 10 changed files with 152 additions and 47 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

All notable changes to this package will be documented in this file.

## [1.4.2] - 2021-07-22

### Fixes:
- [Android] [issue 99](https://github.com/Unity-Technologies/com.unity.mobile.notifications/issues/99) Use FLAG_IMMUTABLE for PendingIntent
- [iOS] Do not touch Plist file unless modifications are required
- [iOS] [1348518](https://issuetracker.unity3d.com/product/unity/issues/guid/1348518) Fix crash in push notification (case )

## [1.4.1] - 2021-05-06

### Fixes:
Expand Down
79 changes: 64 additions & 15 deletions Editor/iOSNotificationPostProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public static void OnPostprocessBuild(BuildTarget buildTarget, string path)

var needLocationFramework = (bool)settings.Find(i => i.Key == "UnityUseLocationNotificationTrigger").Value;
var addPushNotificationCapability = (bool)settings.Find(i => i.Key == "UnityAddRemoteNotificationCapability").Value;

var useReleaseAPSEnv = false;
if (addPushNotificationCapability)
{
Expand All @@ -54,6 +55,8 @@ private static void PatchPBXProject(string path, bool needLocationFramework, boo
{
var pbxProjectPath = PBXProject.GetPBXProjectPath(path);

var needsToWriteChanges = false;

var pbxProject = new PBXProject();
pbxProject.ReadFromString(File.ReadAllText(pbxProjectPath));

Expand All @@ -75,11 +78,19 @@ private static void PatchPBXProject(string path, bool needLocationFramework, boo
}

// Add necessary frameworks.
pbxProject.AddFrameworkToProject(unityFrameworkTarget, "UserNotifications.framework", true);
if (needLocationFramework)
if (!pbxProject.ContainsFramework(unityFrameworkTarget, "UserNotifications.framework"))
{
pbxProject.AddFrameworkToProject(unityFrameworkTarget, "UserNotifications.framework", true);
needsToWriteChanges = true;
}
if (needLocationFramework && !pbxProject.ContainsFramework(unityFrameworkTarget, "CoreLocation.framework"))
{
pbxProject.AddFrameworkToProject(unityFrameworkTarget, "CoreLocation.framework", false);
needsToWriteChanges = true;
}

File.WriteAllText(pbxProjectPath, pbxProject.WriteToString());
if (needsToWriteChanges)
File.WriteAllText(pbxProjectPath, pbxProject.WriteToString());

// Update the entitlements file.
if (addPushNotificationCapability)
Expand All @@ -100,46 +111,84 @@ private static void PatchPBXProject(string path, bool needLocationFramework, boo
private static void PatchPlist(string path, List<Unity.Notifications.NotificationSetting> settings, bool addPushNotificationCapability)
{
var plistPath = path + "/Info.plist";

var plist = new PlistDocument();
plist.ReadFromString(File.ReadAllText(plistPath));

var rootDict = plist.root;
var needsToWriteChanges = false;

// Add all the settings to the plist.
foreach (var setting in settings)
{
if (setting.Value.GetType() == typeof(bool))
rootDict.SetBoolean(setting.Key, (bool)setting.Value);
else if (setting.Value.GetType() == typeof(PresentationOption) || setting.Value.GetType() == typeof(AuthorizationOption))
rootDict.SetInteger(setting.Key, (int)setting.Value);
if (ShouldAddSettingToPlist(setting, rootDict))
{
needsToWriteChanges = true;
if (setting.Value.GetType() == typeof(bool))
{
rootDict.SetBoolean(setting.Key, (bool)setting.Value);
}
else if (setting.Value.GetType() == typeof(PresentationOption) ||
setting.Value.GetType() == typeof(AuthorizationOption))
{
rootDict.SetInteger(setting.Key, (int)setting.Value);
}
}
}

// Add "remote-notification" to the list of supported UIBackgroundModes.
if (addPushNotificationCapability)
{
PlistElementArray currentBacgkgroundModes = (PlistElementArray)rootDict["UIBackgroundModes"];
if (currentBacgkgroundModes == null)
currentBacgkgroundModes = rootDict.CreateArray("UIBackgroundModes");
PlistElementArray currentBackgroundModes = (PlistElementArray)rootDict["UIBackgroundModes"];
if (currentBackgroundModes == null)
currentBackgroundModes = rootDict.CreateArray("UIBackgroundModes");

currentBacgkgroundModes.AddString("remote-notification");
var remoteNotificationElement = new PlistElementString("remote-notification");
if (!currentBackgroundModes.values.Contains(remoteNotificationElement))
{
currentBackgroundModes.values.Add(remoteNotificationElement);
needsToWriteChanges = true;
}
}

File.WriteAllText(plistPath, plist.WriteToString());
if (needsToWriteChanges)
File.WriteAllText(plistPath, plist.WriteToString());
}

// If the plist doesn't contain the key, or it's value is different, we should add/overwrite it.
private static bool ShouldAddSettingToPlist(Unity.Notifications.NotificationSetting setting,
PlistElementDict rootDict)
{
if (!rootDict.values.ContainsKey(setting.Key))
return true;
else if (setting.Value.GetType() == typeof(bool))
return !rootDict.values[setting.Key].AsBoolean().Equals((bool)setting.Value);
else if (setting.Value.GetType() == typeof(PresentationOption) || setting.Value.GetType() == typeof(AuthorizationOption))
return !rootDict.values[setting.Key].AsInteger().Equals((int)setting.Value);
else
return false;
}

private static void PatchPreprocessor(string path, bool needLocationFramework, bool addPushNotificationCapability)
{
var preprocessorPath = path + "/Classes/Preprocessor.h";
var preprocessor = File.ReadAllText(preprocessorPath);
var needsToWriteChanges = false;

if (needLocationFramework && preprocessor.Contains("UNITY_USES_LOCATION"))
{
preprocessor = preprocessor.Replace("UNITY_USES_LOCATION 0", "UNITY_USES_LOCATION 1");
needsToWriteChanges = true;
}

if (addPushNotificationCapability && preprocessor.Contains("UNITY_USES_REMOTE_NOTIFICATIONS"))
preprocessor = preprocessor.Replace("UNITY_USES_REMOTE_NOTIFICATIONS 0", "UNITY_USES_REMOTE_NOTIFICATIONS 1");
{
preprocessor =
preprocessor.Replace("UNITY_USES_REMOTE_NOTIFICATIONS 0", "UNITY_USES_REMOTE_NOTIFICATIONS 1");
needsToWriteChanges = true;
}

File.WriteAllText(preprocessorPath, preprocessor);
if (needsToWriteChanges)
File.WriteAllText(preprocessorPath, preprocessor);
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -242,15 +242,15 @@ public void scheduleNotificationIntent(Intent data_intent_source) {
int id = data_intent.getIntExtra("id", 0);

Intent openAppIntent = UnityNotificationManager.buildOpenAppIntent(data_intent, mContext, mOpenActivity);
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, id, openAppIntent, 0);
PendingIntent pendingIntent = getActivityPendingIntent(mContext, id, openAppIntent, 0);
Intent intent = buildNotificationIntent(mContext, data_intent, pendingIntent);

if (intent != null) {
if (this.mRescheduleOnRestart) {
UnityNotificationManager.saveNotificationIntent(mContext, data_intent);
}

PendingIntent broadcast = PendingIntent.getBroadcast(mContext, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent broadcast = getBroadcastPendingIntent(mContext, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
UnityNotificationManager.scheduleNotificationIntentAlarm(mContext, intent, broadcast);
}
}
Expand All @@ -276,7 +276,7 @@ protected static Intent buildNotificationIntent(Context context, Intent intent,
for (String id : ids) {
// Get the given broadcast PendingIntent by id as request code.
// FLAG_NO_CREATE is set to return null if the described PendingIntent doesn't exist.
PendingIntent broadcast = PendingIntent.getBroadcast(context, Integer.valueOf(id), intent, PendingIntent.FLAG_NO_CREATE);
PendingIntent broadcast = getBroadcastPendingIntent(context, Integer.valueOf(id), intent, PendingIntent.FLAG_NO_CREATE);

if (broadcast != null) {
validNotificationIds.add(id);
Expand All @@ -302,6 +302,20 @@ protected static Intent buildNotificationIntent(Context context, Intent intent,
return data_intent;
}

public static PendingIntent getActivityPendingIntent(Context context, int id, Intent intent, int flags) {
if (Build.VERSION.SDK_INT >= 23)
return PendingIntent.getActivity(context, id, intent, flags | PendingIntent.FLAG_IMMUTABLE);
else
return PendingIntent.getActivity(context, id, intent, flags);
}

public static PendingIntent getBroadcastPendingIntent(Context context, int id, Intent intent, int flags) {
if (Build.VERSION.SDK_INT >= 23)
return PendingIntent.getBroadcast(context, id, intent, flags | PendingIntent.FLAG_IMMUTABLE);
else
return PendingIntent.getBroadcast(context, id, intent, flags);
}

// Save the notification intent to SharedPreferences if reschedule_on_restart is true,
// which will be consumed by UnityNotificationRestartOnBootReceiver for device reboot.
protected static void saveNotificationIntent(Context context, Intent intent) {
Expand Down Expand Up @@ -396,7 +410,7 @@ public int checkNotificationStatus(int id) {
// Check if the pending notification with the given id has been registered.
public boolean checkIfPendingNotificationIsRegistered(int id) {
Intent intent = new Intent(mActivity, UnityNotificationManager.class);
return (PendingIntent.getBroadcast(mContext, id, intent, PendingIntent.FLAG_NO_CREATE) != null);
return (getBroadcastPendingIntent(mContext, id, intent, PendingIntent.FLAG_NO_CREATE) != null);
}

// Cancel all the pending notifications.
Expand Down Expand Up @@ -433,7 +447,7 @@ public void cancelPendingNotificationIntent(int id) {
// Cancel a pending notification by id.
protected static void cancelPendingNotificationIntent(Context context, int id) {
Intent intent = new Intent(context, UnityNotificationManager.class);
PendingIntent broadcast = PendingIntent.getBroadcast(context, id, intent, PendingIntent.FLAG_NO_CREATE);
PendingIntent broadcast = getBroadcastPendingIntent(context, id, intent, PendingIntent.FLAG_NO_CREATE);

if (broadcast != null) {
if (context != null) {
Expand Down
1 change: 0 additions & 1 deletion Runtime/iOS/Plugins/UnityNotificationManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,6 @@ - (void)scheduleLocalNotification:(iOSNotificationData*)data
return;

assert(self.onNotificationReceivedCallback != NULL);
assert(data->userInfo != NULL);

NSDictionary* userInfo = (__bridge_transfer NSDictionary*)data->userInfo;
data->userInfo = NULL;
Expand Down
8 changes: 7 additions & 1 deletion Runtime/iOS/Plugins/UnityNotificationWrapper.m
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,14 @@ bool _GetAppOpenedUsingNotification()
iOSNotificationData* _GetLastNotificationData()
{
UnityNotificationManager* manager = [UnityNotificationManager sharedInstance];
UNNotification* notification = manager.lastReceivedNotification;
if (notification == nil)
return NULL;
UNNotificationRequest* request = notification.request;
if (request == nil)
return NULL;
iOSNotificationData* ret = (iOSNotificationData*)malloc(sizeof(iOSNotificationData));
*ret = UNNotificationRequestToiOSNotificationData(manager.lastReceivedNotification.request);
*ret = UNNotificationRequestToiOSNotificationData(request);
return ret;
}

Expand Down
14 changes: 8 additions & 6 deletions Runtime/iOS/iOSNotification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -364,21 +364,23 @@ public iOSNotification(string identifier)
ForegroundPresentationOption = PresentationOption.Alert | PresentationOption.Sound;
}

internal iOSNotification(iOSNotificationData data)
internal iOSNotification(iOSNotificationWithUserInfo data)
{
this.data = data;
userInfo = iOSNotificationsWrapper.NSDictionaryToCs(data.userInfo);
this.data = data.data;
userInfo = data.userInfo;
}

iOSNotificationData data;
Dictionary<string, string> userInfo;

internal iOSNotificationData GetDataForSending()
internal iOSNotificationWithUserInfo GetDataForSending()
{
if (data.identifier == null)
data.identifier = GenerateUniqueID();
data.userInfo = iOSNotificationsWrapper.CsDictionaryToObjC(userInfo);
return data;
iOSNotificationWithUserInfo ret;
ret.data = data;
ret.userInfo = userInfo;
return ret;
}
}
}
6 changes: 3 additions & 3 deletions Runtime/iOS/iOSNotificationCenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public static iOSNotification[] GetDeliveredNotifications()
return NotificationDataToNotifications(iOSNotificationsWrapper.GetDeliveredNotificationData());
}

private static iOSNotification[] NotificationDataToNotifications(iOSNotificationData[] notificationData)
private static iOSNotification[] NotificationDataToNotifications(iOSNotificationWithUserInfo[] notificationData)
{
var iOSNotifications = new iOSNotification[notificationData == null ? 0 : notificationData.Length];

Expand Down Expand Up @@ -188,13 +188,13 @@ public static iOSNotificationSettings GetNotificationSettings()
return iOSNotificationsWrapper.GetNotificationSettings();
}

internal static void OnReceivedRemoteNotification(iOSNotificationData data)
internal static void OnReceivedRemoteNotification(iOSNotificationWithUserInfo data)
{
var notification = new iOSNotification(data);
s_OnRemoteNotificationReceived(notification);
}

internal static void OnSentNotification(iOSNotificationData data)
internal static void OnSentNotification(iOSNotificationWithUserInfo data)
{
var notification = new iOSNotification(data);
s_OnNotificationReceived(notification);
Expand Down
Loading

0 comments on commit 8b0c223

Please sign in to comment.