From 6c0539381aba4a135b6c3235f6e3d61afe1d0cb3 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Mon, 15 Jun 2020 13:45:11 -0300 Subject: [PATCH 01/28] [WIP] Notification Service --- ios/NotificationService/Info.plist | 33 ++++ .../NotificationService.entitlements | 10 ++ .../NotificationService.swift | 66 ++++++++ ios/RocketChatRN.xcodeproj/project.pbxproj | 150 ++++++++++++++++++ .../xcschemes/NotificationService.xcscheme | 100 ++++++++++++ 5 files changed, 359 insertions(+) create mode 100644 ios/NotificationService/Info.plist create mode 100644 ios/NotificationService/NotificationService.entitlements create mode 100644 ios/NotificationService/NotificationService.swift create mode 100644 ios/RocketChatRN.xcodeproj/xcshareddata/xcschemes/NotificationService.xcscheme diff --git a/ios/NotificationService/Info.plist b/ios/NotificationService/Info.plist new file mode 100644 index 0000000000..496dfc6cec --- /dev/null +++ b/ios/NotificationService/Info.plist @@ -0,0 +1,33 @@ + + + + + AppGroup + group.ios.chat.rocket + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + NotificationService + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + NSExtension + + NSExtensionPointIdentifier + com.apple.usernotifications.service + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).NotificationService + + + diff --git a/ios/NotificationService/NotificationService.entitlements b/ios/NotificationService/NotificationService.entitlements new file mode 100644 index 0000000000..f48f06fbc6 --- /dev/null +++ b/ios/NotificationService/NotificationService.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.ios.chat.rocket + + + diff --git a/ios/NotificationService/NotificationService.swift b/ios/NotificationService/NotificationService.swift new file mode 100644 index 0000000000..da346801b6 --- /dev/null +++ b/ios/NotificationService/NotificationService.swift @@ -0,0 +1,66 @@ +import CoreLocation +import UserNotifications + +class NotificationService: UNNotificationServiceExtension { + + var contentHandler: ((UNNotificationContent) -> Void)? + var bestAttemptContent: UNMutableNotificationContent? + + override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { + self.contentHandler = contentHandler + bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) + + if let bestAttemptContent = bestAttemptContent { + let suiteName = Bundle.main.object(forInfoDictionaryKey: "AppGroup") as! String + let userDefaults = UserDefaults(suiteName: suiteName) + + let ejson = bestAttemptContent.userInfo["ejson"] as! String + + if let data = ejson.data(using: .utf8) { + let json = try? (JSONSerialization.jsonObject(with: data) as! [String: Any]) + if let json = json { + let host = json["host"] as! String + let msgId = json["messageId"] as! String + + let userId = userDefaults?.string(forKey: "reactnativemeteor_usertoken-\(host)")! ?? "" + let token = userDefaults?.string(forKey: "reactnativemeteor_usertoken-\(userId)")! ?? "" + + var urlComponents = URLComponents(string: "\(host)/api/v1/chat.getMessage")! + let queryItems = [URLQueryItem(name: "msgId", value: msgId)] + urlComponents.queryItems = queryItems + + var request = URLRequest(url: urlComponents.url!) + request.httpMethod = "GET" + request.addValue(userId, forHTTPHeaderField: "x-user-id") + request.addValue(token, forHTTPHeaderField: "x-auth-token") + + let task = URLSession.shared.dataTask(with: request) {(data, response, error) in + guard let data = data else { return } + let json = try? (JSONSerialization.jsonObject(with: data) as! [String: Any]) + if let json = json { + if let content = json["message"] as? [String: Any] { + bestAttemptContent.body = content["msg"] as! String + + if let user = content["u"] as? [String: Any] { + bestAttemptContent.title = user["username"] as! String + } + } + } + contentHandler(bestAttemptContent) + } + + task.resume() + } + } + } + } + + override func serviceExtensionTimeWillExpire() { + // Called just before the extension will be terminated by the system. + // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. + if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { + contentHandler(bestAttemptContent) + } + } + +} diff --git a/ios/RocketChatRN.xcodeproj/project.pbxproj b/ios/RocketChatRN.xcodeproj/project.pbxproj index 042345f63c..3e3d4404a1 100644 --- a/ios/RocketChatRN.xcodeproj/project.pbxproj +++ b/ios/RocketChatRN.xcodeproj/project.pbxproj @@ -30,6 +30,8 @@ 1EC6ACF622CBA01500A41C61 /* ShareRocketChatRN.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EC6ACF522CBA01500A41C61 /* ShareRocketChatRN.m */; }; 1ED59D4C22CBA77D00C54289 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1ED59D4B22CBA77D00C54289 /* GoogleService-Info.plist */; }; 1EDDE57A22DFAD8E0078F69D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1EDDE57922DFAD8E0078F69D /* Images.xcassets */; }; + 1EFEB5982493B6640072EDC0 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EFEB5972493B6640072EDC0 /* NotificationService.swift */; }; + 1EFEB59C2493B6640072EDC0 /* NotificationService.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 1EFEB5952493B6640072EDC0 /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 24A2AEF2383D44B586D31C01 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 06BB44DD4855498082A744AD /* libz.tbd */; }; 50046CB6BDA69B9232CF66D9 /* libPods-RocketChatRN.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C235DC7B31A4D1578EDEF219 /* libPods-RocketChatRN.a */; }; 7A006F14229C83B600803143 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 7A006F13229C83B600803143 /* GoogleService-Info.plist */; }; @@ -48,6 +50,13 @@ remoteGlobalIDString = 1EC6ACAF22CB9FC300A41C61; remoteInfo = ShareRocketChatRN; }; + 1EFEB59A2493B6640072EDC0 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1EFEB5942493B6640072EDC0; + remoteInfo = NotificationService; + }; 7AAA749A23043AD300F1ADE9 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 290E43E48AD8418287FA99D6 /* WatermelonDB.xcodeproj */; @@ -65,6 +74,7 @@ dstSubfolderSpec = 13; files = ( 1EC6ACBB22CB9FC300A41C61 /* ShareRocketChatRN.appex in Embed App Extensions */, + 1EFEB59C2493B6640072EDC0 /* NotificationService.appex in Embed App Extensions */, ); name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; @@ -99,6 +109,10 @@ 1EC6AD6022CBA20C00A41C61 /* ShareRocketChatRN.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ShareRocketChatRN.entitlements; sourceTree = ""; }; 1ED59D4B22CBA77D00C54289 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = SOURCE_ROOT; }; 1EDDE57922DFAD8E0078F69D /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 1EFEB5952493B6640072EDC0 /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 1EFEB5972493B6640072EDC0 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; + 1EFEB5992493B6640072EDC0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1EFEB5A12493B67D0072EDC0 /* NotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NotificationService.entitlements; sourceTree = ""; }; 290E43E48AD8418287FA99D6 /* WatermelonDB.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = WatermelonDB.xcodeproj; path = "../node_modules/@nozbe/watermelondb/native/ios/WatermelonDB.xcodeproj"; sourceTree = ""; }; 60B2A6A31FC4588700BD58E5 /* RocketChatRN.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = RocketChatRN.entitlements; path = RocketChatRN/RocketChatRN.entitlements; sourceTree = ""; }; 66D6B1D0567051BE541450C9 /* Pods-RocketChatRN.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RocketChatRN.release.xcconfig"; path = "Pods/Target Support Files/Pods-RocketChatRN/Pods-RocketChatRN.release.xcconfig"; sourceTree = ""; }; @@ -146,6 +160,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 1EFEB5922493B6640072EDC0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -180,6 +201,16 @@ path = ShareRocketChatRN; sourceTree = ""; }; + 1EFEB5962493B6640072EDC0 /* NotificationService */ = { + isa = PBXGroup; + children = ( + 1EFEB5A12493B67D0072EDC0 /* NotificationService.entitlements */, + 1EFEB5972493B6640072EDC0 /* NotificationService.swift */, + 1EFEB5992493B6640072EDC0 /* Info.plist */, + ); + path = NotificationService; + sourceTree = ""; + }; 22CA7F59107E0C79C2506C7C /* Pods */ = { isa = PBXGroup; children = ( @@ -213,6 +244,7 @@ 13B07FAE1A68108700A75B9A /* RocketChatRN */, 832341AE1AAA6A7D00B99B32 /* Libraries */, 1EC6ACB122CB9FC300A41C61 /* ShareRocketChatRN */, + 1EFEB5962493B6640072EDC0 /* NotificationService */, 83CBBA001A601CBA00E9B192 /* Products */, BB4B591B5FC44CD9986DB2A6 /* Frameworks */, AF5E16F0398347E6A80C8CBE /* Resources */, @@ -228,6 +260,7 @@ children = ( 13B07F961A680F5B00A75B9A /* RocketChatRN.app */, 1EC6ACB022CB9FC300A41C61 /* ShareRocketChatRN.appex */, + 1EFEB5952493B6640072EDC0 /* NotificationService.appex */, ); name = Products; sourceTree = ""; @@ -291,6 +324,7 @@ ); dependencies = ( 1EC6ACBA22CB9FC300A41C61 /* PBXTargetDependency */, + 1EFEB59B2493B6640072EDC0 /* PBXTargetDependency */, ); name = RocketChatRN; productName = "Hello World"; @@ -317,6 +351,23 @@ productReference = 1EC6ACB022CB9FC300A41C61 /* ShareRocketChatRN.appex */; productType = "com.apple.product-type.app-extension"; }; + 1EFEB5942493B6640072EDC0 /* NotificationService */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1EFEB5A02493B6640072EDC0 /* Build configuration list for PBXNativeTarget "NotificationService" */; + buildPhases = ( + 1EFEB5912493B6640072EDC0 /* Sources */, + 1EFEB5922493B6640072EDC0 /* Frameworks */, + 1EFEB5932493B6640072EDC0 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = NotificationService; + productName = NotificationService; + productReference = 1EFEB5952493B6640072EDC0 /* NotificationService.appex */; + productType = "com.apple.product-type.app-extension"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -324,6 +375,7 @@ isa = PBXProject; attributes = { DefaultBuildSystemTypeForWorkspace = Original; + LastSwiftUpdateCheck = 1150; LastUpgradeCheck = 1130; ORGANIZATIONNAME = Facebook; TargetAttributes = { @@ -356,6 +408,11 @@ }; }; }; + 1EFEB5942493B6640072EDC0 = { + CreatedOnToolsVersion = 11.5; + DevelopmentTeam = S6UPZG7ZR3; + ProvisioningStyle = Automatic; + }; }; }; buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "RocketChatRN" */; @@ -380,6 +437,7 @@ targets = ( 13B07F861A680F5B00A75B9A /* RocketChatRN */, 1EC6ACAF22CB9FC300A41C61 /* ShareRocketChatRN */, + 1EFEB5942493B6640072EDC0 /* NotificationService */, ); }; /* End PBXProject section */ @@ -417,6 +475,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 1EFEB5932493B6640072EDC0 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -672,6 +737,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 1EFEB5912493B6640072EDC0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1EFEB5982493B6640072EDC0 /* NotificationService.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -680,6 +753,11 @@ target = 1EC6ACAF22CB9FC300A41C61 /* ShareRocketChatRN */; targetProxy = 1EC6ACB922CB9FC300A41C61 /* PBXContainerItemProxy */; }; + 1EFEB59B2493B6640072EDC0 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1EFEB5942493B6640072EDC0 /* NotificationService */; + targetProxy = 1EFEB59A2493B6640072EDC0 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -930,6 +1008,69 @@ }; name = Release; }; + 1EFEB59D2493B6640072EDC0 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = S6UPZG7ZR3; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = NotificationService/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + MARKETING_VERSION = 4.8.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 1EFEB59E2493B6640072EDC0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; + CODE_SIGN_IDENTITY = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = S6UPZG7ZR3; + GCC_C_LANGUAGE_STANDARD = gnu11; + INFOPLIST_FILE = NotificationService/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + MARKETING_VERSION = 4.8.0; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; 83CBBA201A601CBA00E9B192 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1053,6 +1194,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 1EFEB5A02493B6640072EDC0 /* Build configuration list for PBXNativeTarget "NotificationService" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1EFEB59D2493B6640072EDC0 /* Debug */, + 1EFEB59E2493B6640072EDC0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "RocketChatRN" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/ios/RocketChatRN.xcodeproj/xcshareddata/xcschemes/NotificationService.xcscheme b/ios/RocketChatRN.xcodeproj/xcshareddata/xcschemes/NotificationService.xcscheme new file mode 100644 index 0000000000..3fd37eb6a7 --- /dev/null +++ b/ios/RocketChatRN.xcodeproj/xcshareddata/xcschemes/NotificationService.xcscheme @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 088284442706f9f5fe586a012d91344e19d46257 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Tue, 16 Jun 2020 12:52:55 -0300 Subject: [PATCH 02/28] [WIP] Android push notification privacy --- .../chat/rocket/reactnative/Callback.java | 9 ++ .../reactnative/CustomPushNotification.java | 16 +++- .../java/chat/rocket/reactnative/Ejson.java | 1 + .../rocket/reactnative/LoadNotification.java | 93 +++++++++++++++++++ 4 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 android/app/src/main/java/chat/rocket/reactnative/Callback.java create mode 100644 android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java diff --git a/android/app/src/main/java/chat/rocket/reactnative/Callback.java b/android/app/src/main/java/chat/rocket/reactnative/Callback.java new file mode 100644 index 0000000000..1767ce002e --- /dev/null +++ b/android/app/src/main/java/chat/rocket/reactnative/Callback.java @@ -0,0 +1,9 @@ +package chat.rocket.reactnative; + +import android.os.Bundle; + +public class Callback { + public void call(Bundle bundle) { + + } +} diff --git a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java index 17002faa0b..b86a4802a4 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java @@ -33,6 +33,7 @@ import java.util.Map; import java.util.ArrayList; import java.util.Date; +import android.util.Log; import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_EVENT_NAME; @@ -78,6 +79,14 @@ public void onReceived() throws InvalidNotificationException { super.postNotification(Integer.parseInt(notId)); notifyReceivedToJS(); + + notificationLoad(ejson.serverURL(), ejson.messageId, new Callback() { + @Override + public void call(Bundle bundle) { + String title = bundle.getString("title"); + Log.d("ROCKETCHAT", title); + } + }); } @Override @@ -94,12 +103,8 @@ protected Notification.Builder getNotificationBuilder(PendingIntent intent) { Bundle bundle = mNotificationProps.asBundle(); String notId = bundle.getString("notId", "1"); - String title = bundle.getString("title"); - String message = bundle.getString("message"); notification - .setContentTitle(title) - .setContentText(message) .setContentIntent(intent) .setPriority(Notification.PRIORITY_HIGH) .setDefaults(Notification.DEFAULT_ALL) @@ -300,4 +305,7 @@ private void notificationDismiss(Notification.Builder notification, int notifica notification.setDeleteIntent(dismissPendingIntent); } + private void notificationLoad(String server, String messageId, Callback callback) { + LoadNotification.load(reactApplicationContext, server, messageId, callback); + } } diff --git a/android/app/src/main/java/chat/rocket/reactnative/Ejson.java b/android/app/src/main/java/chat/rocket/reactnative/Ejson.java index 48c3703709..f502407a79 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/Ejson.java +++ b/android/app/src/main/java/chat/rocket/reactnative/Ejson.java @@ -8,6 +8,7 @@ public class Ejson { String host; String rid; String type; + String messageId; Sender sender; private String TOKEN_KEY = "reactnativemeteor_usertoken-"; diff --git a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java new file mode 100644 index 0000000000..7ceec1720a --- /dev/null +++ b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java @@ -0,0 +1,93 @@ +package chat.rocket.reactnative; + +import android.os.Bundle; +import android.content.Context; +import android.content.SharedPreferences; + +import okhttp3.Call; +import okhttp3.OkHttpClient; +import okhttp3.HttpUrl; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.Interceptor; + +import com.google.gson.Gson; +import java.io.IOException; + +import com.facebook.react.bridge.ReactApplicationContext; + +import chat.rocket.userdefaults.RNUserDefaultsModule; + +class JsonResponse { + Message message; + + public class Message { + String msg; + U u; + + public class U { + String username; + } + } +} + +public class LoadNotification { + private static int RETRY_COUNT = 0; + private static int[] TIMEOUT = new int[]{ 0, 1, 3, 5, 10 }; + private static String TOKEN_KEY = "reactnativemeteor_usertoken-"; + private static SharedPreferences sharedPreferences = RNUserDefaultsModule.getPreferences(CustomPushNotification.reactApplicationContext); + + public static void load(ReactApplicationContext reactApplicationContext, final String host, final String msgId, Callback callback) { + final OkHttpClient client = new OkHttpClient(); + HttpUrl.Builder url = HttpUrl.parse(host.concat("/api/v1/chat.getMessage")).newBuilder(); + + String userId = sharedPreferences.getString(TOKEN_KEY.concat(host), ""); + String token = sharedPreferences.getString(TOKEN_KEY.concat(userId), ""); + + Request request = new Request.Builder() + .header("x-user-id", userId) + .header("x-auth-token", token) + .url(url.addQueryParameter("msgId", msgId).build()) + .build(); + + runRequest(client, request, callback); + } + + private static void runRequest(OkHttpClient client, Request request, Callback callback) { + try { + Thread.sleep(TIMEOUT[RETRY_COUNT] * 1000); + } catch (InterruptedException ie) { + + } + + client.newCall(request).enqueue(new okhttp3.Callback() { + @Override + public void onFailure(Call call, IOException e) { + if (RETRY_COUNT <= TIMEOUT.length) { + runRequest(client, request, callback); + } + } + + @Override + public void onResponse(Call call, final Response response) throws IOException { + if (!response.isSuccessful()) { + if (RETRY_COUNT <= TIMEOUT.length) { + runRequest(client, request, callback); + } + return; + } + + Gson gson = new Gson(); + JsonResponse json = gson.fromJson(response.body().string(), JsonResponse.class); + + Bundle bundle = new Bundle(); + bundle.putString("title", json.message.u.username); + bundle.putString("message", json.message.msg); + + callback.call(bundle); + } + }); + + RETRY_COUNT++; + } +} \ No newline at end of file From 5356e58fedb5c0121f0e64f44fac0ead4186183b Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Tue, 16 Jun 2020 14:49:18 -0300 Subject: [PATCH 03/28] [WIP] Retry request when it fails (iOS) --- .../NotificationService.swift | 72 ++++++++++++++----- 1 file changed, 56 insertions(+), 16 deletions(-) diff --git a/ios/NotificationService/NotificationService.swift b/ios/NotificationService/NotificationService.swift index da346801b6..a38c2a06db 100644 --- a/ios/NotificationService/NotificationService.swift +++ b/ios/NotificationService/NotificationService.swift @@ -6,6 +6,9 @@ class NotificationService: UNNotificationServiceExtension { var contentHandler: ((UNNotificationContent) -> Void)? var bestAttemptContent: UNMutableNotificationContent? + var retryCount = 0 + var retryTimeout = [1.0, 3.0, 5.0, 10.0] + override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) @@ -34,26 +37,63 @@ class NotificationService: UNNotificationServiceExtension { request.addValue(userId, forHTTPHeaderField: "x-user-id") request.addValue(token, forHTTPHeaderField: "x-auth-token") - let task = URLSession.shared.dataTask(with: request) {(data, response, error) in - guard let data = data else { return } - let json = try? (JSONSerialization.jsonObject(with: data) as! [String: Any]) - if let json = json { - if let content = json["message"] as? [String: Any] { - bestAttemptContent.body = content["msg"] as! String - - if let user = content["u"] as? [String: Any] { - bestAttemptContent.title = user["username"] as! String - } - } - } - contentHandler(bestAttemptContent) - } - - task.resume() + runRequest(request: request, bestAttemptContent: bestAttemptContent, contentHandler: contentHandler) } } } } + + func runRequest(request: URLRequest, bestAttemptContent: UNMutableNotificationContent, contentHandler: @escaping (UNNotificationContent) -> Void) { + let task = URLSession.shared.dataTask(with: request) {(data, response, error) in + + func retryRequest() { + // if we can try again + if self.retryCount < self.retryTimeout.count { + // Try again after X seconds + DispatchQueue.main.asyncAfter(deadline: .now() + self.retryTimeout[self.retryCount], execute: { + self.runRequest(request: request, bestAttemptContent: bestAttemptContent, contentHandler: contentHandler) + self.retryCount += 1; + }) + } + } + + // If some error happened + if error != nil { + retryRequest() + + // Check if the request did successfully + } else if let response = response as? HTTPURLResponse { + // if it not was successfully + if response.statusCode != 200 { + retryRequest() + + // If the response status is 200 + } else { + // Process data + if let data = data { + // Parse data of response + let json = try? (JSONSerialization.jsonObject(with: data) as! [String: Any]) + if let json = json { + // Message + if let content = json["message"] as? [String: Any] { + // Message -> Msg + bestAttemptContent.body = content["msg"] as! String + + // Message -> U -> Username + if let user = content["u"] as? [String: Any] { + bestAttemptContent.title = user["username"] as! String + } + } + } + // Show notification with the content modified + contentHandler(bestAttemptContent) + } + } + } + } + + task.resume() + } override func serviceExtensionTimeWillExpire() { // Called just before the extension will be terminated by the system. From 406ec7b9e04c937d40b6d6a60d41ff52ef454582 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Tue, 16 Jun 2020 17:36:28 -0300 Subject: [PATCH 04/28] [WIP] Override notification bundle --- .../reactnative/CustomPushNotification.java | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java index b86a4802a4..c451aee64a 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java @@ -55,10 +55,9 @@ public static void clearMessages(int notId) { @Override public void onReceived() throws InvalidNotificationException { - final Bundle bundle = mNotificationProps.asBundle(); + Bundle bundle = mNotificationProps.asBundle(); String notId = bundle.getString("notId", "1"); - String title = bundle.getString("title"); if (notificationMessages.get(notId) == null) { notificationMessages.put(notId, new ArrayList()); @@ -67,24 +66,22 @@ public void onReceived() throws InvalidNotificationException { Gson gson = new Gson(); Ejson ejson = gson.fromJson(bundle.getString("ejson", "{}"), Ejson.class); - boolean hasSender = ejson.sender != null; - - bundle.putLong("time", new Date().getTime()); - bundle.putString("username", hasSender ? ejson.sender.username : title); - bundle.putString("senderId", hasSender ? ejson.sender._id : "1"); - bundle.putString("avatarUri", ejson.getAvatarUri()); - - notificationMessages.get(notId).add(bundle); - - super.postNotification(Integer.parseInt(notId)); - - notifyReceivedToJS(); - notificationLoad(ejson.serverURL(), ejson.messageId, new Callback() { @Override - public void call(Bundle bundle) { + public void call(Bundle value) { + bundle.putAll(value); + + boolean hasSender = ejson.sender != null; String title = bundle.getString("title"); - Log.d("ROCKETCHAT", title); + + bundle.putLong("time", new Date().getTime()); + bundle.putString("username", !hasSender ? ejson.sender.username : title); + bundle.putString("senderId", hasSender ? ejson.sender._id : "1"); + bundle.putString("avatarUri", ejson.getAvatarUri()); + + notificationMessages.get(notId).add(bundle); + notifyReceivedToJS(); + postNotification(Integer.parseInt(notId)); } }); } From 0a34daacb4f5224d7fe2b47c13f1b8fcf60ceb0e Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Tue, 16 Jun 2020 17:40:03 -0300 Subject: [PATCH 05/28] [CHORE] Remove unnecessary import --- .../java/chat/rocket/reactnative/CustomPushNotification.java | 1 - 1 file changed, 1 deletion(-) diff --git a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java index c451aee64a..53fa7bdf1b 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java @@ -33,7 +33,6 @@ import java.util.Map; import java.util.ArrayList; import java.util.Date; -import android.util.Log; import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_EVENT_NAME; From 738007d010a809b1744200960b03bd4503d2816c Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Mon, 22 Jun 2020 11:52:35 -0300 Subject: [PATCH 06/28] [WIP] Check notification Type (iOS) --- ios/NotificationService/NotificationService.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ios/NotificationService/NotificationService.swift b/ios/NotificationService/NotificationService.swift index a38c2a06db..1b6fd14eab 100644 --- a/ios/NotificationService/NotificationService.swift +++ b/ios/NotificationService/NotificationService.swift @@ -14,6 +14,14 @@ class NotificationService: UNNotificationServiceExtension { bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) if let bestAttemptContent = bestAttemptContent { + let type = bestAttemptContent.userInfo["type"] as! String + + // If the notification have the content at her payload, show it + if type != "message-hidden" { + contentHandler(bestAttemptContent); + return; + } + let suiteName = Bundle.main.object(forInfoDictionaryKey: "AppGroup") as! String let userDefaults = UserDefaults(suiteName: suiteName) @@ -99,6 +107,8 @@ class NotificationService: UNNotificationServiceExtension { // Called just before the extension will be terminated by the system. // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { + bestAttemptContent.title = "Error" + bestAttemptContent.body = "Can't fetch a message from your server" contentHandler(bestAttemptContent) } } From f1ecc7e19ca4faa22a15f5f0b9d0e27392e94106 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Tue, 23 Jun 2020 15:23:14 -0300 Subject: [PATCH 07/28] [WIP] Change to notification endpoint --- .../reactnative/CustomPushNotification.java | 48 ++++++++++------- .../rocket/reactnative/LoadNotification.java | 20 +++---- .../NotificationService.swift | 53 +++++++++---------- .../react-native-notifications+2.1.7.patch | 13 +++++ 4 files changed, 72 insertions(+), 62 deletions(-) diff --git a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java index 53fa7bdf1b..66dbe8dc35 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java @@ -54,35 +54,43 @@ public static void clearMessages(int notId) { @Override public void onReceived() throws InvalidNotificationException { - Bundle bundle = mNotificationProps.asBundle(); + Bundle received = mNotificationProps.asBundle(); - String notId = bundle.getString("notId", "1"); + String notId = received.getString("notId", "1"); if (notificationMessages.get(notId) == null) { notificationMessages.put(notId, new ArrayList()); } + String server = received.getString("server", ""); + String msgId = received.getString("msgId", ""); + String type = received.getString("type", ""); + + if (type.equals("message-hidden")) { + notificationLoad(server, msgId, new Callback() { + @Override + public void call(Bundle bundle) { + mNotificationProps = createProps(bundle); + } + }); + } + + Bundle bundle = mNotificationProps.asBundle(); + Gson gson = new Gson(); Ejson ejson = gson.fromJson(bundle.getString("ejson", "{}"), Ejson.class); - notificationLoad(ejson.serverURL(), ejson.messageId, new Callback() { - @Override - public void call(Bundle value) { - bundle.putAll(value); - - boolean hasSender = ejson.sender != null; - String title = bundle.getString("title"); - - bundle.putLong("time", new Date().getTime()); - bundle.putString("username", !hasSender ? ejson.sender.username : title); - bundle.putString("senderId", hasSender ? ejson.sender._id : "1"); - bundle.putString("avatarUri", ejson.getAvatarUri()); - - notificationMessages.get(notId).add(bundle); - notifyReceivedToJS(); - postNotification(Integer.parseInt(notId)); - } - }); + boolean hasSender = ejson.sender != null; + String title = bundle.getString("title"); + + bundle.putLong("time", new Date().getTime()); + bundle.putString("username", !hasSender ? ejson.sender.username : title); + bundle.putString("senderId", hasSender ? ejson.sender._id : "1"); + bundle.putString("avatarUri", ejson.getAvatarUri()); + + notificationMessages.get(notId).add(bundle); + postNotification(Integer.parseInt(notId)); + notifyReceivedToJS(); } @Override diff --git a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java index 7ceec1720a..15868bb7e0 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java @@ -19,16 +19,9 @@ import chat.rocket.userdefaults.RNUserDefaultsModule; class JsonResponse { - Message message; - - public class Message { - String msg; - U u; - - public class U { - String username; - } - } + String title; + String message; + String ejson; } public class LoadNotification { @@ -39,7 +32,7 @@ public class LoadNotification { public static void load(ReactApplicationContext reactApplicationContext, final String host, final String msgId, Callback callback) { final OkHttpClient client = new OkHttpClient(); - HttpUrl.Builder url = HttpUrl.parse(host.concat("/api/v1/chat.getMessage")).newBuilder(); + HttpUrl.Builder url = HttpUrl.parse(host.concat("/notification")).newBuilder(); String userId = sharedPreferences.getString(TOKEN_KEY.concat(host), ""); String token = sharedPreferences.getString(TOKEN_KEY.concat(userId), ""); @@ -81,8 +74,9 @@ public void onResponse(Call call, final Response response) throws IOException { JsonResponse json = gson.fromJson(response.body().string(), JsonResponse.class); Bundle bundle = new Bundle(); - bundle.putString("title", json.message.u.username); - bundle.putString("message", json.message.msg); + bundle.putString("title", json.title); + bundle.putString("message", json.message); + bundle.putString("ejson", json.ejson); callback.call(bundle); } diff --git a/ios/NotificationService/NotificationService.swift b/ios/NotificationService/NotificationService.swift index 1b6fd14eab..6f3feb1ca0 100644 --- a/ios/NotificationService/NotificationService.swift +++ b/ios/NotificationService/NotificationService.swift @@ -25,29 +25,22 @@ class NotificationService: UNNotificationServiceExtension { let suiteName = Bundle.main.object(forInfoDictionaryKey: "AppGroup") as! String let userDefaults = UserDefaults(suiteName: suiteName) - let ejson = bestAttemptContent.userInfo["ejson"] as! String + let server = bestAttemptContent.userInfo["server"] as! String + let msgId = bestAttemptContent.userInfo["msgId"] as! String - if let data = ejson.data(using: .utf8) { - let json = try? (JSONSerialization.jsonObject(with: data) as! [String: Any]) - if let json = json { - let host = json["host"] as! String - let msgId = json["messageId"] as! String - - let userId = userDefaults?.string(forKey: "reactnativemeteor_usertoken-\(host)")! ?? "" - let token = userDefaults?.string(forKey: "reactnativemeteor_usertoken-\(userId)")! ?? "" + let userId = userDefaults?.string(forKey: "reactnativemeteor_usertoken-\(server)")! ?? "" + let token = userDefaults?.string(forKey: "reactnativemeteor_usertoken-\(userId)")! ?? "" - var urlComponents = URLComponents(string: "\(host)/api/v1/chat.getMessage")! - let queryItems = [URLQueryItem(name: "msgId", value: msgId)] - urlComponents.queryItems = queryItems - - var request = URLRequest(url: urlComponents.url!) - request.httpMethod = "GET" - request.addValue(userId, forHTTPHeaderField: "x-user-id") - request.addValue(token, forHTTPHeaderField: "x-auth-token") + var urlComponents = URLComponents(string: "\(server)/notification")! + let queryItems = [URLQueryItem(name: "msgId", value: msgId)] + urlComponents.queryItems = queryItems + + var request = URLRequest(url: urlComponents.url!) + request.httpMethod = "GET" + request.addValue(userId, forHTTPHeaderField: "x-user-id") + request.addValue(token, forHTTPHeaderField: "x-auth-token") - runRequest(request: request, bestAttemptContent: bestAttemptContent, contentHandler: contentHandler) - } - } + runRequest(request: request, bestAttemptContent: bestAttemptContent, contentHandler: contentHandler) } } @@ -82,15 +75,17 @@ class NotificationService: UNNotificationServiceExtension { // Parse data of response let json = try? (JSONSerialization.jsonObject(with: data) as! [String: Any]) if let json = json { - // Message - if let content = json["message"] as? [String: Any] { - // Message -> Msg - bestAttemptContent.body = content["msg"] as! String - - // Message -> U -> Username - if let user = content["u"] as? [String: Any] { - bestAttemptContent.title = user["username"] as! String - } + // Title + if let title = json["title"] as? String { + bestAttemptContent.title = title + } + // Body + if let body = json["message"] as? String { + bestAttemptContent.body = body + } + // Ejson + if let ejson = json["ejson"] as? String { + bestAttemptContent.userInfo["ejson"] = ejson; } } // Show notification with the content modified diff --git a/patches/react-native-notifications+2.1.7.patch b/patches/react-native-notifications+2.1.7.patch index 021a525b25..fe34efcc7a 100644 --- a/patches/react-native-notifications+2.1.7.patch +++ b/patches/react-native-notifications+2.1.7.patch @@ -104,6 +104,19 @@ index edc4fd4..7cd77f6 100644 } @end +diff --git a/node_modules/react-native-notifications/android/app/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java b/node_modules/react-native-notifications/android/app/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java +index 524ff07..70f22d5 100644 +--- a/node_modules/react-native-notifications/android/app/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java ++++ b/node_modules/react-native-notifications/android/app/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java +@@ -31,7 +31,7 @@ public class PushNotification implements IPushNotification { + final protected AppLifecycleFacade mAppLifecycleFacade; + final protected AppLaunchHelper mAppLaunchHelper; + final protected JsIOHelper mJsIOHelper; +- final protected PushNotificationProps mNotificationProps; ++ protected PushNotificationProps mNotificationProps; + final protected AppVisibilityListener mAppVisibilityListener = new AppVisibilityListener() { + @Override + public void onAppVisible() { diff --git a/node_modules/react-native-notifications/android/app/src/reactNative59/java/com/wix/reactnativenotifications/NotificationManagerCompatFacade.java b/node_modules/react-native-notifications/android/app/src/reactNative59/java/com/wix/reactnativenotifications/NotificationManagerCompatFacade.java index f9c858b..94ea188 100644 --- a/node_modules/react-native-notifications/android/app/src/reactNative59/java/com/wix/reactnativenotifications/NotificationManagerCompatFacade.java From 54e604be8357c4d70d26eeab3954a64763f1aa1c Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Tue, 23 Jun 2020 15:37:45 -0300 Subject: [PATCH 08/28] eof --- .../src/main/java/chat/rocket/reactnative/LoadNotification.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java index 15868bb7e0..e023485f72 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java @@ -84,4 +84,4 @@ public void onResponse(Call call, final Response response) throws IOException { RETRY_COUNT++; } -} \ No newline at end of file +} From 690fa5c2ce65712e87ac5657c0cfae9fd6f261ff Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Tue, 23 Jun 2020 17:25:07 -0300 Subject: [PATCH 09/28] fix unwrap conditional value --- ios/NotificationService/NotificationService.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/NotificationService/NotificationService.swift b/ios/NotificationService/NotificationService.swift index 6f3feb1ca0..efc83a5e5a 100644 --- a/ios/NotificationService/NotificationService.swift +++ b/ios/NotificationService/NotificationService.swift @@ -14,7 +14,7 @@ class NotificationService: UNNotificationServiceExtension { bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) if let bestAttemptContent = bestAttemptContent { - let type = bestAttemptContent.userInfo["type"] as! String + let type = bestAttemptContent.userInfo["type"] as? String ?? "" // If the notification have the content at her payload, show it if type != "message-hidden" { From 05c120d04db9d526598d9e5f6615d1219d45c20a Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Wed, 24 Jun 2020 14:11:26 -0300 Subject: [PATCH 10/28] turn run request synchronous --- .../rocket/reactnative/LoadNotification.java | 41 +++++++------------ 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java index e023485f72..72c6f6fca0 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java @@ -49,39 +49,28 @@ public static void load(ReactApplicationContext reactApplicationContext, final S private static void runRequest(OkHttpClient client, Request request, Callback callback) { try { Thread.sleep(TIMEOUT[RETRY_COUNT] * 1000); - } catch (InterruptedException ie) { - } - - client.newCall(request).enqueue(new okhttp3.Callback() { - @Override - public void onFailure(Call call, IOException e) { - if (RETRY_COUNT <= TIMEOUT.length) { - runRequest(client, request, callback); - } + Response response = client.newCall(request).execute(); + String body = response.body().string(); + if (!response.isSuccessful()) { + throw new Exception("Error"); } - @Override - public void onResponse(Call call, final Response response) throws IOException { - if (!response.isSuccessful()) { - if (RETRY_COUNT <= TIMEOUT.length) { - runRequest(client, request, callback); - } - return; - } + Gson gson = new Gson(); + JsonResponse json = gson.fromJson(body, JsonResponse.class); - Gson gson = new Gson(); - JsonResponse json = gson.fromJson(response.body().string(), JsonResponse.class); + Bundle bundle = new Bundle(); + bundle.putString("title", json.message.u.username); + bundle.putString("message", json.message.msg); - Bundle bundle = new Bundle(); - bundle.putString("title", json.title); - bundle.putString("message", json.message); - bundle.putString("ejson", json.ejson); + callback.call(bundle); - callback.call(bundle); + } catch (Exception e) { + if (RETRY_COUNT <= TIMEOUT.length) { + runRequest(client, request, callback); } - }); + } RETRY_COUNT++; } -} +} \ No newline at end of file From 872560ed05f0384b8a00055f0468c599da8112b2 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Wed, 24 Jun 2020 14:21:56 -0300 Subject: [PATCH 11/28] fix bundle info --- .../main/java/chat/rocket/reactnative/LoadNotification.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java index 72c6f6fca0..1580e66ad6 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java @@ -60,8 +60,9 @@ private static void runRequest(OkHttpClient client, Request request, Callback ca JsonResponse json = gson.fromJson(body, JsonResponse.class); Bundle bundle = new Bundle(); - bundle.putString("title", json.message.u.username); - bundle.putString("message", json.message.msg); + bundle.putString("title", json.title); + bundle.putString("message", json.message); + bundle.putString("ejson", json.ejson); callback.call(bundle); From 9317795ee8a1534d12257223f83af460d150afff Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Wed, 24 Jun 2020 17:39:08 -0300 Subject: [PATCH 12/28] eof --- .../src/main/java/chat/rocket/reactnative/LoadNotification.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java index 1580e66ad6..4497b62784 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java @@ -74,4 +74,4 @@ private static void runRequest(OkHttpClient client, Request request, Callback ca RETRY_COUNT++; } -} \ No newline at end of file +} From 1b1e431b9ec633b7f7da18f93997a1395b9689ca Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Wed, 24 Jun 2020 17:39:48 -0300 Subject: [PATCH 13/28] remove extra tab --- .../java/chat/rocket/reactnative/CustomPushNotification.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java index 66dbe8dc35..0fdfec176b 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java @@ -87,7 +87,7 @@ public void call(Bundle bundle) { bundle.putString("username", !hasSender ? ejson.sender.username : title); bundle.putString("senderId", hasSender ? ejson.sender._id : "1"); bundle.putString("avatarUri", ejson.getAvatarUri()); - + notificationMessages.get(notId).add(bundle); postNotification(Integer.parseInt(notId)); notifyReceivedToJS(); From 78839b7b26361137e063894889954a2db7e2994b Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Wed, 24 Jun 2020 17:40:47 -0300 Subject: [PATCH 14/28] undo unnecessary change --- android/app/src/main/java/chat/rocket/reactnative/Ejson.java | 1 - 1 file changed, 1 deletion(-) diff --git a/android/app/src/main/java/chat/rocket/reactnative/Ejson.java b/android/app/src/main/java/chat/rocket/reactnative/Ejson.java index f502407a79..48c3703709 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/Ejson.java +++ b/android/app/src/main/java/chat/rocket/reactnative/Ejson.java @@ -8,7 +8,6 @@ public class Ejson { String host; String rid; String type; - String messageId; Sender sender; private String TOKEN_KEY = "reactnativemeteor_usertoken-"; From 767ffb9797db61eeba4144d50ad22be4069c5ea8 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Wed, 24 Jun 2020 17:45:32 -0300 Subject: [PATCH 15/28] remove not working code for a while --- ios/NotificationService/NotificationService.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/ios/NotificationService/NotificationService.swift b/ios/NotificationService/NotificationService.swift index efc83a5e5a..717f8b72b9 100644 --- a/ios/NotificationService/NotificationService.swift +++ b/ios/NotificationService/NotificationService.swift @@ -102,8 +102,6 @@ class NotificationService: UNNotificationServiceExtension { // Called just before the extension will be terminated by the system. // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { - bestAttemptContent.title = "Error" - bestAttemptContent.body = "Can't fetch a message from your server" contentHandler(bestAttemptContent) } } From b57aa254a29aa5e06505e747f6e34f6d1156a3c2 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Wed, 24 Jun 2020 17:49:41 -0300 Subject: [PATCH 16/28] fix notification title --- .../java/chat/rocket/reactnative/CustomPushNotification.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java index 0fdfec176b..2f22d5abc6 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java @@ -84,7 +84,7 @@ public void call(Bundle bundle) { String title = bundle.getString("title"); bundle.putLong("time", new Date().getTime()); - bundle.putString("username", !hasSender ? ejson.sender.username : title); + bundle.putString("username", hasSender ? ejson.sender.username : title); bundle.putString("senderId", hasSender ? ejson.sender._id : "1"); bundle.putString("avatarUri", ejson.getAvatarUri()); From 5cd7c770a9c53de8d0a655d3051a8a7fcdd24dd4 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Tue, 21 Jul 2020 10:23:09 -0300 Subject: [PATCH 17/28] change endpoint and received/sent data --- .../chat/rocket/reactnative/CustomPushNotification.java | 4 ++-- .../java/chat/rocket/reactnative/LoadNotification.java | 4 ++-- ios/NotificationService/NotificationService.swift | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java index 2f22d5abc6..58deef5b7f 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java @@ -64,9 +64,9 @@ public void onReceived() throws InvalidNotificationException { String server = received.getString("server", ""); String msgId = received.getString("msgId", ""); - String type = received.getString("type", ""); + String notificationType = received.getString("notificationType", ""); - if (type.equals("message-hidden")) { + if (notificationType.equals("message-id-only")) { notificationLoad(server, msgId, new Callback() { @Override public void call(Bundle bundle) { diff --git a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java index 4497b62784..f9d2e8feed 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java @@ -32,7 +32,7 @@ public class LoadNotification { public static void load(ReactApplicationContext reactApplicationContext, final String host, final String msgId, Callback callback) { final OkHttpClient client = new OkHttpClient(); - HttpUrl.Builder url = HttpUrl.parse(host.concat("/notification")).newBuilder(); + HttpUrl.Builder url = HttpUrl.parse(host.concat("/api/v1/push.get")).newBuilder(); String userId = sharedPreferences.getString(TOKEN_KEY.concat(host), ""); String token = sharedPreferences.getString(TOKEN_KEY.concat(userId), ""); @@ -40,7 +40,7 @@ public static void load(ReactApplicationContext reactApplicationContext, final S Request request = new Request.Builder() .header("x-user-id", userId) .header("x-auth-token", token) - .url(url.addQueryParameter("msgId", msgId).build()) + .url(url.addQueryParameter("id", msgId).build()) .build(); runRequest(client, request, callback); diff --git a/ios/NotificationService/NotificationService.swift b/ios/NotificationService/NotificationService.swift index 717f8b72b9..d46e052b6a 100644 --- a/ios/NotificationService/NotificationService.swift +++ b/ios/NotificationService/NotificationService.swift @@ -14,10 +14,10 @@ class NotificationService: UNNotificationServiceExtension { bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) if let bestAttemptContent = bestAttemptContent { - let type = bestAttemptContent.userInfo["type"] as? String ?? "" + let notificationType = bestAttemptContent.userInfo["notificationType"] as? String ?? "" // If the notification have the content at her payload, show it - if type != "message-hidden" { + if notificationType != "message-id-only" { contentHandler(bestAttemptContent); return; } @@ -31,8 +31,8 @@ class NotificationService: UNNotificationServiceExtension { let userId = userDefaults?.string(forKey: "reactnativemeteor_usertoken-\(server)")! ?? "" let token = userDefaults?.string(forKey: "reactnativemeteor_usertoken-\(userId)")! ?? "" - var urlComponents = URLComponents(string: "\(server)/notification")! - let queryItems = [URLQueryItem(name: "msgId", value: msgId)] + var urlComponents = URLComponents(string: "\(server)/api/v1/push.get")! + let queryItems = [URLQueryItem(name: "id", value: msgId)] urlComponents.queryItems = queryItems var request = URLRequest(url: urlComponents.url!) From 29162ca474262354ce5060a2c719330900903c9e Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Wed, 22 Jul 2020 15:05:06 -0300 Subject: [PATCH 18/28] message-id-only working properly on android --- .../reactnative/CustomPushNotification.java | 33 +++++++--------- .../java/chat/rocket/reactnative/Ejson.java | 2 + .../rocket/reactnative/LoadNotification.java | 39 +++++++++++++++---- 3 files changed, 47 insertions(+), 27 deletions(-) diff --git a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java index 58deef5b7f..90d0a88764 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java @@ -15,7 +15,7 @@ import android.os.Bundle; import android.app.Person; -import com.google.gson.*; +import com.google.gson.Gson; import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.bitmap.RoundedCorners; import com.bumptech.glide.request.RequestOptions; @@ -55,19 +55,10 @@ public static void clearMessages(int notId) { @Override public void onReceived() throws InvalidNotificationException { Bundle received = mNotificationProps.asBundle(); + Ejson receivedEjson = new Gson().fromJson(received.getString("ejson", "{}"), Ejson.class); - String notId = received.getString("notId", "1"); - - if (notificationMessages.get(notId) == null) { - notificationMessages.put(notId, new ArrayList()); - } - - String server = received.getString("server", ""); - String msgId = received.getString("msgId", ""); - String notificationType = received.getString("notificationType", ""); - - if (notificationType.equals("message-id-only")) { - notificationLoad(server, msgId, new Callback() { + if (receivedEjson.notificationType.equals("message-id-only")) { + notificationLoad(receivedEjson.serverURL(), receivedEjson.messageId, new Callback() { @Override public void call(Bundle bundle) { mNotificationProps = createProps(bundle); @@ -75,18 +66,22 @@ public void call(Bundle bundle) { }); } + // We should re-read these values since that can be changed by notificationLoad Bundle bundle = mNotificationProps.asBundle(); + Ejson loadedEjson = new Gson().fromJson(bundle.getString("ejson", "{}"), Ejson.class); + String notId = bundle.getString("notId", "1"); - Gson gson = new Gson(); - Ejson ejson = gson.fromJson(bundle.getString("ejson", "{}"), Ejson.class); + if (notificationMessages.get(notId) == null) { + notificationMessages.put(notId, new ArrayList()); + } - boolean hasSender = ejson.sender != null; + boolean hasSender = loadedEjson.sender != null; String title = bundle.getString("title"); bundle.putLong("time", new Date().getTime()); - bundle.putString("username", hasSender ? ejson.sender.username : title); - bundle.putString("senderId", hasSender ? ejson.sender._id : "1"); - bundle.putString("avatarUri", ejson.getAvatarUri()); + bundle.putString("username", hasSender ? loadedEjson.sender.username : title); + bundle.putString("senderId", hasSender ? loadedEjson.sender._id : "1"); + bundle.putString("avatarUri", loadedEjson.getAvatarUri()); notificationMessages.get(notId).add(bundle); postNotification(Integer.parseInt(notId)); diff --git a/android/app/src/main/java/chat/rocket/reactnative/Ejson.java b/android/app/src/main/java/chat/rocket/reactnative/Ejson.java index 48c3703709..0c68e47559 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/Ejson.java +++ b/android/app/src/main/java/chat/rocket/reactnative/Ejson.java @@ -9,6 +9,8 @@ public class Ejson { String rid; String type; Sender sender; + String messageId; + String notificationType; private String TOKEN_KEY = "reactnativemeteor_usertoken-"; private SharedPreferences sharedPreferences = RNUserDefaultsModule.getPreferences(CustomPushNotification.reactApplicationContext); diff --git a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java index f9d2e8feed..0fc8fc5eeb 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java @@ -19,9 +19,32 @@ import chat.rocket.userdefaults.RNUserDefaultsModule; class JsonResponse { - String title; - String message; - String ejson; + Data data; + + class Data { + Notification notification; + + class Notification { + String notId; + String title; + String text; + Payload payload; + + class Payload { + String host; + String rid; + String type; + Sender sender; + String messageId; + String notificationType; + + class Sender { + String username; + String _id; + } + } + } + } } public class LoadNotification { @@ -60,18 +83,18 @@ private static void runRequest(OkHttpClient client, Request request, Callback ca JsonResponse json = gson.fromJson(body, JsonResponse.class); Bundle bundle = new Bundle(); - bundle.putString("title", json.title); - bundle.putString("message", json.message); - bundle.putString("ejson", json.ejson); + bundle.putString("notId", json.data.notification.notId); + bundle.putString("title", json.data.notification.title); + bundle.putString("message", json.data.notification.text); + bundle.putString("ejson", gson.toJson(json.data.notification.payload)); callback.call(bundle); } catch (Exception e) { if (RETRY_COUNT <= TIMEOUT.length) { + RETRY_COUNT++; runRequest(client, request, callback); } } - - RETRY_COUNT++; } } From 0b69382e23ead7ac37c119172d7a0e31acc19a0a Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Wed, 22 Jul 2020 17:14:23 -0300 Subject: [PATCH 19/28] notification privacy working on ios --- .../NotificationService.swift | 86 ++++++++++++++----- 1 file changed, 63 insertions(+), 23 deletions(-) diff --git a/ios/NotificationService/NotificationService.swift b/ios/NotificationService/NotificationService.swift index d46e052b6a..240b4f6f8a 100644 --- a/ios/NotificationService/NotificationService.swift +++ b/ios/NotificationService/NotificationService.swift @@ -1,6 +1,38 @@ import CoreLocation import UserNotifications +struct PushResponse: Decodable { + let success: Bool + let data: Data + + struct Data: Decodable { + let notification: Notification + + struct Notification: Decodable { + let notId: Int + let title: String + let text: String + let payload: Payload + + struct Payload: Decodable, Encodable { + let host: String + let rid: String? + let type: String? + let sender: Sender? + let messageId: String + let notificationType: String? + let name: String? + + struct Sender: Decodable, Encodable { + let _id: String + let username: String + let name: String + } + } + } + } +} + class NotificationService: UNNotificationServiceExtension { var contentHandler: ((UNNotificationContent) -> Void)? @@ -12,22 +44,30 @@ class NotificationService: UNNotificationServiceExtension { override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) - + if let bestAttemptContent = bestAttemptContent { - let notificationType = bestAttemptContent.userInfo["notificationType"] as? String ?? "" + let ejson = (bestAttemptContent.userInfo["ejson"] as? String ?? "").data(using: .utf8)! + guard let data = try? (JSONDecoder().decode(PushResponse.Data.Notification.Payload.self, from: ejson)) else { + return + } + + let notificationType = data.notificationType ?? "" // If the notification have the content at her payload, show it if notificationType != "message-id-only" { - contentHandler(bestAttemptContent); - return; + contentHandler(bestAttemptContent) + return } let suiteName = Bundle.main.object(forInfoDictionaryKey: "AppGroup") as! String let userDefaults = UserDefaults(suiteName: suiteName) - let server = bestAttemptContent.userInfo["server"] as! String - let msgId = bestAttemptContent.userInfo["msgId"] as! String - + var server = data.host + if (server.last == "/") { + server.removeLast() + } + let msgId = data.messageId + let userId = userDefaults?.string(forKey: "reactnativemeteor_usertoken-\(server)")! ?? "" let token = userDefaults?.string(forKey: "reactnativemeteor_usertoken-\(userId)")! ?? "" @@ -53,7 +93,7 @@ class NotificationService: UNNotificationServiceExtension { // Try again after X seconds DispatchQueue.main.asyncAfter(deadline: .now() + self.retryTimeout[self.retryCount], execute: { self.runRequest(request: request, bestAttemptContent: bestAttemptContent, contentHandler: contentHandler) - self.retryCount += 1; + self.retryCount += 1 }) } } @@ -73,24 +113,24 @@ class NotificationService: UNNotificationServiceExtension { // Process data if let data = data { // Parse data of response - let json = try? (JSONSerialization.jsonObject(with: data) as! [String: Any]) - if let json = json { - // Title - if let title = json["title"] as? String { - bestAttemptContent.title = title - } - // Body - if let body = json["message"] as? String { - bestAttemptContent.body = body - } - // Ejson - if let ejson = json["ejson"] as? String { - bestAttemptContent.userInfo["ejson"] = ejson; + let push = try? (JSONDecoder().decode(PushResponse.self, from: data)) + if let push = push { + if push.success { + bestAttemptContent.title = push.data.notification.title + bestAttemptContent.body = push.data.notification.text + + let payload = try? (JSONEncoder().encode(push.data.notification.payload)) + if let payload = payload { + bestAttemptContent.userInfo["ejson"] = String(data: payload, encoding: .utf8) ?? "{}" + } + + // Show notification with the content modified + contentHandler(bestAttemptContent) + return } } - // Show notification with the content modified - contentHandler(bestAttemptContent) } + retryRequest() } } } From 4a62812af952a8eedb1ca33261ecbce74347fc38 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Wed, 22 Jul 2020 17:24:13 -0300 Subject: [PATCH 20/28] invalidate circleCI yarn cache --- package.json | 2 +- yarn.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index d992a27280..d89d194fde 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "react-native-modal": "11.5.6", "react-native-navigation-bar-color": "2.0.1", "react-native-notifications": "2.1.7", - "react-native-notifier": "^1.3.1", + "react-native-notifier": "1.3.1", "react-native-orientation-locker": "1.1.8", "react-native-picker-select": "7.0.0", "react-native-platform-touchable": "^1.1.1", diff --git a/yarn.lock b/yarn.lock index f9a717d55b..824cacda3b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12785,7 +12785,7 @@ react-native-notifications@2.1.7: core-js "^1.0.0" uuid "^2.0.3" -react-native-notifier@^1.3.1: +react-native-notifier@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/react-native-notifier/-/react-native-notifier-1.3.1.tgz#a878c82c8ee99b04d57818401b1f084232729afd" integrity sha512-w7KOTF5WOYzbhCXQHz6p9tbosOVxhOW+Sh7VAdIuW6r7PSoryRNkF4P6Bzq1+2NPtMK7L6xnojCdKJ+nVnwh+A== From 64e08ef1bb909b91ebc286a8ea857942f5c4bd0e Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Thu, 23 Jul 2020 10:04:59 -0300 Subject: [PATCH 21/28] Fix provisioning profiles --- ios/RocketChatRN.xcodeproj/project.pbxproj | 15 +++++++-------- ios/fastlane/Fastfile | 1 + 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ios/RocketChatRN.xcodeproj/project.pbxproj b/ios/RocketChatRN.xcodeproj/project.pbxproj index 59d2633288..e210bb6d7c 100644 --- a/ios/RocketChatRN.xcodeproj/project.pbxproj +++ b/ios/RocketChatRN.xcodeproj/project.pbxproj @@ -411,7 +411,7 @@ 1EFEB5942493B6640072EDC0 = { CreatedOnToolsVersion = 11.5; DevelopmentTeam = S6UPZG7ZR3; - ProvisioningStyle = Automatic; + ProvisioningStyle = Manual; }; }; }; @@ -923,7 +923,7 @@ "$(inherited)", "$(SRCROOT)/../node_modules/rn-extensions-share/ios/**", "$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase/**", - "$PODS_CONFIGURATION_BUILD_DIR/Firebase", + $PODS_CONFIGURATION_BUILD_DIR/Firebase, ); INFOPLIST_FILE = ShareRocketChatRN/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 11.0; @@ -989,7 +989,7 @@ "$(inherited)", "$(SRCROOT)/../node_modules/rn-extensions-share/ios/**", "$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase/**", - "$PODS_CONFIGURATION_BUILD_DIR/Firebase", + $PODS_CONFIGURATION_BUILD_DIR/Firebase, ); INFOPLIST_FILE = ShareRocketChatRN/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 11.0; @@ -1022,9 +1022,7 @@ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = S6UPZG7ZR3; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -1036,6 +1034,7 @@ MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = "chat.rocket.reactnative.NotificationService Development"; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -1055,8 +1054,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = S6UPZG7ZR3; @@ -1068,6 +1066,7 @@ MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = "chat.rocket.reactnative.NotificationService AppStore"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile index 3461925b79..46de9f08bb 100644 --- a/ios/fastlane/Fastfile +++ b/ios/fastlane/Fastfile @@ -49,6 +49,7 @@ platform :ios do type: "appstore" ) # more information: https://codesigning.guide get_provisioning_profile(app_identifier: "chat.rocket.reactnative.ShareExtension") + get_provisioning_profile(app_identifier: "chat.rocket.reactnative.NotificationService") pem() gym(scheme: "RocketChatRN", workspace: "RocketChatRN.xcworkspace") # Build your app - more options available # frameit From 43608b88fc1309b405e292da22d821ddc11b575e Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Thu, 23 Jul 2020 11:59:55 -0300 Subject: [PATCH 22/28] fix notification service version --- ios/RocketChatRN.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/RocketChatRN.xcodeproj/project.pbxproj b/ios/RocketChatRN.xcodeproj/project.pbxproj index e210bb6d7c..c04d7e73df 100644 --- a/ios/RocketChatRN.xcodeproj/project.pbxproj +++ b/ios/RocketChatRN.xcodeproj/project.pbxproj @@ -1029,7 +1029,7 @@ INFOPLIST_FILE = NotificationService/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 4.8.0; + MARKETING_VERSION = 4.10.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService; @@ -1062,7 +1062,7 @@ INFOPLIST_FILE = NotificationService/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 11.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 4.8.0; + MARKETING_VERSION = 4.10.0; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = chat.rocket.reactnative.NotificationService; PRODUCT_NAME = "$(TARGET_NAME)"; From 3506b5299c6d7c2952874b28d742958668a600a2 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Thu, 23 Jul 2020 13:55:40 -0300 Subject: [PATCH 23/28] fix unwrap nil --- ios/NotificationService/NotificationService.swift | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ios/NotificationService/NotificationService.swift b/ios/NotificationService/NotificationService.swift index 240b4f6f8a..28db4ec60d 100644 --- a/ios/NotificationService/NotificationService.swift +++ b/ios/NotificationService/NotificationService.swift @@ -68,8 +68,13 @@ class NotificationService: UNNotificationServiceExtension { } let msgId = data.messageId - let userId = userDefaults?.string(forKey: "reactnativemeteor_usertoken-\(server)")! ?? "" - let token = userDefaults?.string(forKey: "reactnativemeteor_usertoken-\(userId)")! ?? "" + let userId = userDefaults?.string(forKey: "reactnativemeteor_usertoken-\(server)") ?? "" + let token = userDefaults?.string(forKey: "reactnativemeteor_usertoken-\(userId)") ?? "" + + if userId.isEmpty || token.isEmpty { + contentHandler(bestAttemptContent) + return + } var urlComponents = URLComponents(string: "\(server)/api/v1/push.get")! let queryItems = [URLQueryItem(name: "id", value: msgId)] From 080463842e4f383289f505a64588630c746d75d7 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Fri, 24 Jul 2020 12:00:20 -0300 Subject: [PATCH 24/28] compatibility older servers android --- .../java/chat/rocket/reactnative/CustomPushNotification.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java index 90d0a88764..1bfe7ddc4c 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java @@ -57,7 +57,7 @@ public void onReceived() throws InvalidNotificationException { Bundle received = mNotificationProps.asBundle(); Ejson receivedEjson = new Gson().fromJson(received.getString("ejson", "{}"), Ejson.class); - if (receivedEjson.notificationType.equals("message-id-only")) { + if (receivedEjson.notificationType != null && receivedEjson.notificationType.equals("message-id-only")) { notificationLoad(receivedEjson.serverURL(), receivedEjson.messageId, new Callback() { @Override public void call(Bundle bundle) { From f7ef3551d471994aa0b875c2d9a3647d317e83ad Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Fri, 24 Jul 2020 13:20:53 -0300 Subject: [PATCH 25/28] show received notification when cant fetch content from server --- .../java/chat/rocket/reactnative/CustomPushNotification.java | 4 +++- .../main/java/chat/rocket/reactnative/LoadNotification.java | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java index 1bfe7ddc4c..e6574c5d65 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java @@ -61,7 +61,9 @@ public void onReceived() throws InvalidNotificationException { notificationLoad(receivedEjson.serverURL(), receivedEjson.messageId, new Callback() { @Override public void call(Bundle bundle) { - mNotificationProps = createProps(bundle); + if (bundle != null) { + mNotificationProps = createProps(bundle); + } } }); } diff --git a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java index 0fc8fc5eeb..ae714561db 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java @@ -94,6 +94,8 @@ private static void runRequest(OkHttpClient client, Request request, Callback ca if (RETRY_COUNT <= TIMEOUT.length) { RETRY_COUNT++; runRequest(client, request, callback); + } else { + callback.call(null); } } } From 3772973493b8db62cab7b8b5ac733dafef334c74 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Fri, 24 Jul 2020 15:12:19 -0300 Subject: [PATCH 26/28] undo some android changes --- .../java/chat/rocket/reactnative/CustomPushNotification.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java index e6574c5d65..dc74f3b875 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java @@ -104,8 +104,12 @@ protected Notification.Builder getNotificationBuilder(PendingIntent intent) { Bundle bundle = mNotificationProps.asBundle(); String notId = bundle.getString("notId", "1"); + String title = bundle.getString("title"); + String message = bundle.getString("message"); notification + .setContentTitle(title) + .setContentText(message) .setContentIntent(intent) .setPriority(Notification.PRIORITY_HIGH) .setDefaults(Notification.DEFAULT_ALL) From 0550fff1eb4581431dd16f371178a8116c24aeed Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Fri, 24 Jul 2020 16:39:25 -0300 Subject: [PATCH 27/28] prevent group & reply fallback notifications --- .../main/java/chat/rocket/reactnative/Callback.java | 3 ++- .../rocket/reactnative/CustomPushNotification.java | 13 ++++++++++--- .../chat/rocket/reactnative/LoadNotification.java | 1 + 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/android/app/src/main/java/chat/rocket/reactnative/Callback.java b/android/app/src/main/java/chat/rocket/reactnative/Callback.java index 1767ce002e..2c2b2833a0 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/Callback.java +++ b/android/app/src/main/java/chat/rocket/reactnative/Callback.java @@ -1,9 +1,10 @@ package chat.rocket.reactnative; import android.os.Bundle; +import androidx.annotation.Nullable; public class Callback { - public void call(Bundle bundle) { + public void call(@Nullable Bundle bundle) { } } diff --git a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java index dc74f3b875..16f85f5714 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java @@ -14,6 +14,7 @@ import android.os.Build; import android.os.Bundle; import android.app.Person; +import androidx.annotation.Nullable; import com.google.gson.Gson; import com.bumptech.glide.Glide; @@ -60,7 +61,7 @@ public void onReceived() throws InvalidNotificationException { if (receivedEjson.notificationType != null && receivedEjson.notificationType.equals("message-id-only")) { notificationLoad(receivedEjson.serverURL(), receivedEjson.messageId, new Callback() { @Override - public void call(Bundle bundle) { + public void call(@Nullable Bundle bundle) { if (bundle != null) { mNotificationProps = createProps(bundle); } @@ -106,6 +107,8 @@ protected Notification.Builder getNotificationBuilder(PendingIntent intent) { String notId = bundle.getString("notId", "1"); String title = bundle.getString("title"); String message = bundle.getString("message"); + Boolean notificationLoaded = bundle.getBoolean("notificationLoaded", false); + Ejson ejson = new Gson().fromJson(bundle.getString("ejson", "{}"), Ejson.class); notification .setContentTitle(title) @@ -119,10 +122,14 @@ protected Notification.Builder getNotificationBuilder(PendingIntent intent) { notificationColor(notification); notificationChannel(notification); notificationIcons(notification, bundle); - notificationStyle(notification, notificationId, bundle); - notificationReply(notification, notificationId, bundle); notificationDismiss(notification, notificationId); + // if notificationType is null (RC < 3.5) or notificationType is different of message-id-only or notification was loaded successfully + if (ejson.notificationType == null || !ejson.notificationType.equals("message-id-only") || notificationLoaded) { + notificationStyle(notification, notificationId, bundle); + notificationReply(notification, notificationId, bundle); + } + return notification; } diff --git a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java index ae714561db..b80dfb7f61 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/LoadNotification.java @@ -87,6 +87,7 @@ private static void runRequest(OkHttpClient client, Request request, Callback ca bundle.putString("title", json.data.notification.title); bundle.putString("message", json.data.notification.text); bundle.putString("ejson", gson.toJson(json.data.notification.payload)); + bundle.putBoolean("notificationLoaded", true); callback.call(bundle); From 4a2267000eae3e44728c0674089f12b57f80e1f4 Mon Sep 17 00:00:00 2001 From: Djorkaeff Alexandre Date: Fri, 24 Jul 2020 17:47:08 -0300 Subject: [PATCH 28/28] dont show more than one fallback notification by server --- .../reactnative/CustomPushNotification.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java index 16f85f5714..401314d777 100644 --- a/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java +++ b/android/app/src/main/java/chat/rocket/reactnative/CustomPushNotification.java @@ -34,15 +34,18 @@ import java.util.Map; import java.util.ArrayList; import java.util.Date; +import java.util.Iterator; import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_EVENT_NAME; public class CustomPushNotification extends PushNotification { public static ReactApplicationContext reactApplicationContext; + final NotificationManager notificationManager; public CustomPushNotification(Context context, Bundle bundle, AppLifecycleFacade appLifecycleFacade, AppLaunchHelper appLaunchHelper, JsIOHelper jsIoHelper) { super(context, bundle, appLifecycleFacade, appLaunchHelper, jsIoHelper); reactApplicationContext = new ReactApplicationContext(context); + notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); } private static Map> notificationMessages = new HashMap>(); @@ -128,6 +131,26 @@ protected Notification.Builder getNotificationBuilder(PendingIntent intent) { if (ejson.notificationType == null || !ejson.notificationType.equals("message-id-only") || notificationLoaded) { notificationStyle(notification, notificationId, bundle); notificationReply(notification, notificationId, bundle); + + // message couldn't be loaded from server (Fallback notification) + } else { + Gson gson = new Gson(); + // iterate over the current notification ids to dismiss fallback notifications from same server + for (Map.Entry> bundleList : notificationMessages.entrySet()) { + // iterate over the notifications with this id (same host + rid) + Iterator iterator = bundleList.getValue().iterator(); + while (iterator.hasNext()) { + Bundle not = (Bundle) iterator.next(); + // get the notification info + Ejson notEjson = gson.fromJson(not.getString("ejson", "{}"), Ejson.class); + // if already has a notification from same server + if (ejson.serverURL().equals(notEjson.serverURL())) { + String id = not.getString("notId"); + // cancel this notification + notificationManager.cancel(Integer.parseInt(id)); + } + } + } } return notification;