From a4541c8af3ea545cc4f2750ba0a095ec39dcfcfe Mon Sep 17 00:00:00 2001 From: Dmitry Novotochinov Date: Fri, 29 Jun 2018 15:28:46 +0300 Subject: [PATCH] [#3352] Improve new message notifications * Set custom sound * Tap on notification opens chat * Show message notifications when app in foreground Signed-off-by: Dmitry Novotochinov --- CHANGELOG.md | 1 + android/app/build.gradle | 14 +- android/app/src/debug/res/raw/message.wav | Bin 0 -> 79314 bytes android/app/src/main/AndroidManifest.xml | 22 ++- .../im/status/ethereum/MainApplication.java | 8 +- android/app/src/main/res/raw/message.wav | Bin 0 -> 79314 bytes android/app/src/main/res/values/strings.xml | 1 + android/build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- android/settings.gradle | 4 +- clj-rn.conf.edn | 2 +- ios/Podfile | 12 +- ios/Podfile.lock | 74 +++++--- ios/StatusIm.xcodeproj/project.pbxproj | 132 +++++++------- ios/StatusIm/AppDelegate.h | 4 +- ios/StatusIm/AppDelegate.m | 32 ++-- mobile_files/package-lock.json | 100 ++++++++++- mobile_files/package.json | 2 +- .../react_native/js_dependencies.cljs | 3 +- .../react_native/js_dependencies.cljs | 2 +- src/status_im/android/core.cljs | 3 +- src/status_im/chat/models/message.cljs | 23 ++- src/status_im/ios/core.cljs | 3 +- src/status_im/translations/en.cljs | 4 + .../ui/screens/accounts/login/models.cljs | 4 +- src/status_im/ui/screens/db.cljs | 12 +- src/status_im/ui/screens/events.cljs | 27 +-- src/status_im/utils/config.cljs | 1 + src/status_im/utils/notifications.cljs | 169 +++++++++++++++--- .../react_native/js_dependencies.cljs | 4 +- .../status_im/test/utils/notifications.cljs | 37 ++++ 31 files changed, 507 insertions(+), 197 deletions(-) create mode 100644 android/app/src/debug/res/raw/message.wav create mode 100644 android/app/src/main/res/raw/message.wav create mode 100644 test/cljs/status_im/test/utils/notifications.cljs diff --git a/CHANGELOG.md b/CHANGELOG.md index 1053f4a4db..0dda19ecc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Added refresh button - Added more dapps - Allow for setting custom network id +- Sound for Push Notifications, tap on PN opens corresponding chat ### Fixed - Fixed Sign in: Cannot paste text within password field [#3931] diff --git a/android/app/build.gradle b/android/app/build.gradle index 9cfc4c02f9..eb3f3f1338 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -201,6 +201,7 @@ configurations.all { } dependencies { + implementation project(':react-native-firebase') implementation project(':react-native-background-timer') implementation project(':react-native-svg') implementation 'com.android.support:multidex:1.0.2' @@ -224,9 +225,10 @@ dependencies { implementation project(':react-native-securerandom') implementation project(':react-native-webview-bridge') implementation project(':react-native-config') - implementation project(':react-native-fcm') - implementation 'com.google.firebase:firebase-core:10.0.1' //this decides your firebase SDK version - compile project(':react-native-testfairy') + implementation 'com.google.android.gms:play-services-base:15.0.0' + implementation 'com.google.firebase:firebase-core:15.0.2' //this decides your firebase SDK version + implementation 'com.google.firebase:firebase-messaging:15.0.2' + implementation project(':react-native-testfairy') implementation project(':react-native-keychain') implementation project(':instabug-reactnative') @@ -240,9 +242,6 @@ task copyDownloadableDepsToLibs(type: Copy) { into 'libs' } -// Must be at bottom to avoid dependency collision -apply plugin: "com.google.gms.google-services" - task hemroidBuild(type: Exec) { def rootDir = project.rootDir def localProperties = new File(rootDir, "local.properties") @@ -259,3 +258,6 @@ task hemroidBuild(type: Exec) { } preBuild.dependsOn hemroidBuild + +// Must be at bottom to avoid dependency collision +apply plugin: "com.google.gms.google-services" diff --git a/android/app/src/debug/res/raw/message.wav b/android/app/src/debug/res/raw/message.wav new file mode 100644 index 0000000000000000000000000000000000000000..13c9628295b274116e24231301beb99821ce7ea9 GIT binary patch literal 79314 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 + + @@ -34,8 +36,14 @@ android:largeHeap="true"> + android:name="com.google.firebase.messaging.default_notification_icon" + android:resource="@drawable/ic_stat_status_notification" /> + + + + - - + - + - - + - + diff --git a/android/app/src/main/java/im/status/ethereum/MainApplication.java b/android/app/src/main/java/im/status/ethereum/MainApplication.java index fc7a4c18db..98e7d61534 100644 --- a/android/app/src/main/java/im/status/ethereum/MainApplication.java +++ b/android/app/src/main/java/im/status/ethereum/MainApplication.java @@ -4,11 +4,13 @@ import android.support.multidex.MultiDexApplication; import com.aakashns.reactnativedialogs.ReactNativeDialogsPackage; import org.devio.rn.splashscreen.SplashScreenReactPackage; import com.facebook.react.ReactApplication; +import io.invertase.firebase.RNFirebasePackage; +import io.invertase.firebase.messaging.RNFirebaseMessagingPackage; +import io.invertase.firebase.notifications.RNFirebaseNotificationsPackage; import net.rhogan.rnsecurerandom.RNSecureRandomPackage; import com.instabug.reactlibrary.RNInstabugReactnativePackage; import com.ocetnik.timer.BackgroundTimerPackage; import com.horcrux.svg.SvgPackage; -import com.evollu.react.fcm.FIRMessagingPackage; import com.lugg.ReactNativeConfig.ReactNativeConfigPackage; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; @@ -55,10 +57,12 @@ public class MainApplication extends MultiDexApplication implements ReactApplica Function callRPC = statusPackage.getCallRPC(); List packages = new ArrayList(Arrays.asList( new MainReactPackage(), + new RNFirebasePackage(), + new RNFirebaseMessagingPackage(), + new RNFirebaseNotificationsPackage(), new RNSecureRandomPackage(), new BackgroundTimerPackage(), new SvgPackage(), - new FIRMessagingPackage(), new HttpServerReactPackage(), new SplashScreenReactPackage(), statusPackage, diff --git a/android/app/src/main/res/raw/message.wav b/android/app/src/main/res/raw/message.wav new file mode 100644 index 0000000000000000000000000000000000000000..13c9628295b274116e24231301beb99821ce7ea9 GIT binary patch literal 79314 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 phone appears to be ROOTED, by pressing CONTINUE you understand and accept the risks in using this software. Continue Exit + status-im \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 5897663cf4..ce165e78fa 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -17,7 +17,6 @@ buildscript { allprojects { repositories { - google() mavenLocal() jcenter() maven { url "$rootDir/../node_modules/react-native/android" } @@ -26,5 +25,6 @@ allprojects { flatDir { dirs 'libs' } maven { url "http://139.162.11.12:8081/artifactory/libs-release-local" } maven { url "https://jitpack.io" } + google() } } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 6cd43a0b7a..63ada59e8d 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/android/settings.gradle b/android/settings.gradle index 90863bfbc1..829e18ce9d 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,4 +1,6 @@ rootProject.name = 'StatusIm' +include ':react-native-firebase' +project(':react-native-firebase').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-firebase/android') include ':react-native-securerandom' project(':react-native-securerandom').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-securerandom/android') include ':instabug-reactnative' @@ -7,8 +9,6 @@ include ':react-native-background-timer' project(':react-native-background-timer').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-background-timer/android') include ':react-native-svg' project(':react-native-svg').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-svg/android') -include ':react-native-fcm' -project(':react-native-fcm').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fcm/android') include ':app' include ':react-native-http-bridge' project(':react-native-http-bridge').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-http-bridge/android') diff --git a/clj-rn.conf.edn b/clj-rn.conf.edn index 1777db66d8..47cb7e075f 100644 --- a/clj-rn.conf.edn +++ b/clj-rn.conf.edn @@ -19,7 +19,7 @@ "react-native-image-crop-picker" "react-native-securerandom" "react-native-webview-bridge" - "react-native-fcm" + "react-native-firebase" "homoglyph-finder" "web3" "chance" diff --git a/ios/Podfile b/ios/Podfile index 6e2524763f..a9c57a9222 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,22 +1,14 @@ # Uncomment the next line to define a global platform for your project # platform :ios, '9.0' -# Need to explicitly declare this avoid downgrade -# https://github.com/evollu/react-native-fcm/issues/420 -#pod 'Firebase/Core', '4.0.0' - -# react-native-fcm should support FB 4, but latest breaks builds, hence older version -# TODO(oskarth): Awaiting RN 0.47 upgrade, and/or PN working on iOS device before deciding which version to use -#pod 'Firebase/Messaging' -#pod 'Firebase/Messaging', '3.17.0' - target 'StatusIm' do platform :ios, '8.0' # Uncomment the next line if you're using Swift or would like to use dynamic frameworks # use_frameworks! # Pods for StatusIm - pod 'FirebaseMessaging' + pod 'Firebase/Core' + pod 'Firebase/Messaging' pod 'React', :path => '../node_modules/react-native' pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga' diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 0535b77ebb..5b6c6d3f05 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,24 +1,37 @@ PODS: - - FirebaseAnalytics (4.0.1): - - FirebaseCore (~> 4.0) - - FirebaseInstanceID (~> 2.0) - - "GoogleToolboxForMac/NSData+zlib (~> 2.1)" - - FirebaseCore (4.0.2): - - "GoogleToolboxForMac/NSData+zlib (~> 2.1)" - - FirebaseInstanceID (2.0.0): - - FirebaseCore (~> 4.0) - - FirebaseMessaging (2.0.0): - - FirebaseAnalytics (~> 4.0) - - FirebaseCore (~> 4.0) - - FirebaseInstanceID (~> 2.0) + - Firebase/Core (5.0.1): + - Firebase/CoreOnly + - FirebaseAnalytics (= 5.0.0) + - Firebase/CoreOnly (5.0.1): + - FirebaseCore (= 5.0.1) + - Firebase/Messaging (5.0.1): + - Firebase/CoreOnly + - FirebaseMessaging (= 3.0.0) + - FirebaseAnalytics (5.0.0): + - FirebaseCore (~> 5.0) + - FirebaseInstanceID (~> 3.0) + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - nanopb (~> 0.3) + - FirebaseCore (5.0.1): + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - FirebaseInstanceID (3.0.0): + - FirebaseCore (~> 5.0) + - FirebaseMessaging (3.0.0): + - FirebaseCore (~> 5.0) + - FirebaseInstanceID (~> 3.0) - GoogleToolboxForMac/Logger (~> 2.1) - Protobuf (~> 3.1) - - GoogleToolboxForMac/Defines (2.1.1) - - GoogleToolboxForMac/Logger (2.1.1): - - GoogleToolboxForMac/Defines (= 2.1.1) - - "GoogleToolboxForMac/NSData+zlib (2.1.1)": - - GoogleToolboxForMac/Defines (= 2.1.1) - - Protobuf (3.3.0) + - GoogleToolboxForMac/Defines (2.1.4) + - GoogleToolboxForMac/Logger (2.1.4): + - GoogleToolboxForMac/Defines (= 2.1.4) + - GoogleToolboxForMac/NSData+zlib (2.1.4): + - GoogleToolboxForMac/Defines (= 2.1.4) + - nanopb (0.3.8): + - nanopb/decode (= 0.3.8) + - nanopb/encode (= 0.3.8) + - nanopb/decode (0.3.8) + - nanopb/encode (0.3.8) + - Protobuf (3.5.0) - React (0.55.4): - React/Core (= 0.55.4) - react-native-background-timer (2.0.0): @@ -30,7 +43,8 @@ PODS: - yoga (0.55.4.React) DEPENDENCIES: - - FirebaseMessaging + - Firebase/Core + - Firebase/Messaging - React (from `../node_modules/react-native`) - react-native-background-timer (from `../node_modules/react-native-background-timer`) - RNKeychain (from `../node_modules/react-native-keychain`) @@ -49,24 +63,26 @@ EXTERNAL SOURCES: React: :path: "../node_modules/react-native" react-native-background-timer: - :path: "../node_modules/react-native-background-timer" + :path: ../node_modules/react-native-background-timer RNKeychain: - :path: "../node_modules/react-native-keychain" + :path: ../node_modules/react-native-keychain yoga: :path: "../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: - FirebaseAnalytics: 4d7040fefc3cd8b291cde35f12cf063d7963f15d - FirebaseCore: 1a8bf6c795ad07d2918278657954ffd2552e9c17 - FirebaseInstanceID: 9fbf536668f4d3f0880e7438456dabd1376e294b - FirebaseMessaging: 227406c05b0dc9290702d2e9f18ab5528f0c2cf2 - GoogleToolboxForMac: 8e329f1b599f2512c6b10676d45736bcc2cbbeb0 - Protobuf: d582fecf68201eac3d79ed61369ef45734394b9c + Firebase: d6861c2059d8c32d1e6dd8932e22ada346d90a3a + FirebaseAnalytics: 19812b49fa5f283dd6b23edf8a14b5d477029ab8 + FirebaseCore: cafc814b2d84fc8733f09e653041cc2165332ad7 + FirebaseInstanceID: 83e0040351565df711a5db3d8ebe5ea21aca998a + FirebaseMessaging: f2360a966ecfb0d14facf0fbdf306efc2df0ddbe + GoogleToolboxForMac: 91c824d21e85b31c2aae9bb011c5027c9b4e738f + nanopb: 5601e6bca2dbf1ed831b519092ec110f66982ca3 + Protobuf: 8a9838fba8dae3389230e1b7f8c104aa32389c03 React: aa2040dbb6f317b95314968021bd2888816e03d5 react-native-background-timer: 63dcbf37dbcf294b5c6c071afcdc661fa06a7594 RNKeychain: 627c6095cef215dd3d9804a9a9cf45ab96aa3997 yoga: a23273df0088bf7f2bb7e5d7b00044ea57a2a54a -PODFILE CHECKSUM: 58fa7be75df3ece53c570dbd30d721f4b6d77137 +PODFILE CHECKSUM: 7d2c351f8b90d3ad2b11fdcfde727875f4c2eebf -COCOAPODS: 1.5.3 +COCOAPODS: 1.4.0 diff --git a/ios/StatusIm.xcodeproj/project.pbxproj b/ios/StatusIm.xcodeproj/project.pbxproj index c83a02db28..4c252bb21b 100644 --- a/ios/StatusIm.xcodeproj/project.pbxproj +++ b/ios/StatusIm.xcodeproj/project.pbxproj @@ -33,22 +33,18 @@ 25DC9C9DC25846BD8D084888 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B9A886A2CB448B1ABA0EB62 /* libc++.tbd */; }; 3A8BF31C42291E324219071C /* InstabugCore.framework in Embed Instabug Framework */ = {isa = PBXBuildFile; fileRef = EA36FD18BC2ECACF0A8B83DE /* InstabugCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 3E15DFEC1F6F4D7CAE088F49 /* libTcpSockets.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C2A4E93F6B154AEFA3485B45 /* libTcpSockets.a */; }; + 475D202F20B7450D00879A77 /* libRNFirebase.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 475D1FC020B7413500879A77 /* libRNFirebase.a */; }; 4C16DE0C1F89508700AA10DB /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C16DE0B1F89508700AA10DB /* JavaScriptCore.framework */; }; 4CA4DA1B206D105D006A98B0 /* libRNInstabug.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E3F1C121DDAE781005E4779 /* libRNInstabug.a */; }; - 5974D2035B8B47E0946B63B6 /* libRNFIRMessaging.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F752F17B1E04216B1337A72 /* libRNFIRMessaging.a */; }; 63AE4174241B852A045FAE1F /* InstabugCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA36FD18BC2ECACF0A8B83DE /* InstabugCore.framework */; }; 74B758FC20D7C00B003343C3 /* launch-image-universal.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 74B758FB20D7C00B003343C3 /* launch-image-universal.storyboard */; }; 81C6E6AE0AA739BE9D87C1D0 /* libPods-StatusImTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FC1CBCFE6C906043D6CCEEE1 /* libPods-StatusImTests.a */; }; 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; 8E55E6877F950B81C8D711C5 /* libPods-StatusIm.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 101A4045637A2ADF57D28EF5 /* libPods-StatusIm.a */; }; 91446A820DA5E1C15C24D2A7 /* Instabug.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22D72275B7ADF9FC3304DCE5 /* Instabug.framework */; }; - 925C1F471F7B73B20063DFA0 /* FirebaseCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 925C1F401F7B73B20063DFA0 /* FirebaseCore.framework */; }; - 925C1F481F7B73B20063DFA0 /* FirebaseCoreDiagnostics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 925C1F411F7B73B20063DFA0 /* FirebaseCoreDiagnostics.framework */; }; - 925C1F491F7B73B20063DFA0 /* FirebaseInstanceID.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 925C1F421F7B73B20063DFA0 /* FirebaseInstanceID.framework */; }; - 925C1F4A1F7B73B20063DFA0 /* FirebaseNanoPB.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 925C1F431F7B73B20063DFA0 /* FirebaseNanoPB.framework */; }; 925C1F4C1F7B73B20063DFA0 /* nanopb.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 925C1F451F7B73B20063DFA0 /* nanopb.framework */; }; - 925C1F811F7B73C00063DFA0 /* FirebaseMessaging.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 925C1F7F1F7B73C00063DFA0 /* FirebaseMessaging.framework */; }; 92A0DF7D1F4DE3A4002051BC /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 92A0DF491F4DE3A0002051BC /* GoogleService-Info.plist */; }; + 983F077E2119C9D2004133ED /* message.wav in Resources */ = {isa = PBXBuildFile; fileRef = 983F07442119C9D2004133ED /* message.wav */; }; 98482A6F2065257B00263651 /* libReactNativeTestFairy.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9880471C20650CBC00CEBFE0 /* libReactNativeTestFairy.a */; }; 9E0B01A11DDC5DA7002B0359 /* SF-UI-Text-Light.otf in Resources */ = {isa = PBXBuildFile; fileRef = 9E0B01A01DDC5DA7002B0359 /* SF-UI-Text-Light.otf */; }; 9E3AB6D01D87DB2B008846B4 /* libReact-Native-Webview-Bridge.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E3AB6C61D87DA2B008846B4 /* libReact-Native-Webview-Bridge.a */; }; @@ -189,6 +185,20 @@ remoteGlobalIDString = F60690131CA2766F0003FB26; remoteInfo = RealmReact; }; + 475D1EF120B73EE000879A77 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = AF409BB755B94FB1BBA01927 /* RNSecureRandom.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RNSecureRandom; + }; + 475D1FBF20B7413500879A77 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 475D1F8D20B7413500879A77 /* RNFirebase.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RNFirebase; + }; 5537E2A920650E640085CED4 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; @@ -217,13 +227,6 @@ remoteGlobalIDString = 58B5119B1A9E6C1200147676; remoteInfo = RCTText; }; - 922C4C4A1F4D5C3F0033C753 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = F89A8F8005874B86B63C22E3 /* RNFIRMessaging.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RNFIRMessaging; - }; 92925B671F571DE600203EEB /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1E74DC52A1E449A2BA858B14 /* RNSVG.xcodeproj */; @@ -329,13 +332,6 @@ remoteGlobalIDString = B29EC9CC1E48BED600704A36; remoteInfo = RCTHttpServer; }; - C20F3A6E20E5165B00757214 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = AF409BB755B94FB1BBA01927 /* RNSecureRandom.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RNSecureRandom; - }; C90047CC1FC47AF50002B8EA /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */; @@ -537,6 +533,7 @@ 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 00E356F21AD99517003FC87E /* StatusImTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StatusImTests.m; sourceTree = ""; }; 064351D2FD901F8B6C9AE2A5 /* Pods-StatusImTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-StatusImTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-StatusImTests/Pods-StatusImTests.debug.xcconfig"; sourceTree = ""; }; + 0A9C79F2FD464877A7CC0BC2 /* libRNFirebase.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFirebase.a; sourceTree = ""; }; 101A4045637A2ADF57D28EF5 /* libPods-StatusIm.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-StatusIm.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 11632AA0A5F84F029DD91797 /* libRNVectorIcons.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNVectorIcons.a; sourceTree = ""; }; 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = "../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj"; sourceTree = ""; }; @@ -566,6 +563,9 @@ 3A7EB0491DD9CABC00A4FCC8 /* SplashScreen.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SplashScreen.xcodeproj; path = "../node_modules/react-native-splash-screen/ios/SplashScreen.xcodeproj"; sourceTree = ""; }; 439B6B4B407A4E2AACAFE5BE /* RCTStatus.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RCTStatus.xcodeproj; path = "../modules/react-native-status/ios/RCTStatus/RCTStatus.xcodeproj"; sourceTree = ""; }; 46E2F6052EB44C698C680894 /* RNI18n.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNI18n.xcodeproj; path = "../node_modules/react-native-i18n/ios/RNI18n.xcodeproj"; sourceTree = ""; }; + 475D1F8D20B7413500879A77 /* RNFirebase.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RNFirebase.xcodeproj; path = "../node_modules/react-native-firebase/ios/RNFirebase.xcodeproj"; sourceTree = ""; }; + 475D1FCD20B7415300879A77 /* libFirebaseCore.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libFirebaseCore.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 475D1FCE20B7415300879A77 /* libFirebaseMessaging.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libFirebaseMessaging.a; sourceTree = BUILT_PRODUCTS_DIR; }; 4C16DE0B1F89508700AA10DB /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; 4E586E1B0E544F64AA9F5BD1 /* libz.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; 4EC426A98043452BB6F9C134 /* libRNInstabug.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNInstabug.a; sourceTree = ""; }; @@ -586,6 +586,7 @@ 925C1F451F7B73B20063DFA0 /* nanopb.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = nanopb.framework; sourceTree = ""; }; 925C1F7F1F7B73C00063DFA0 /* FirebaseMessaging.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = FirebaseMessaging.framework; sourceTree = ""; }; 92A0DF491F4DE3A0002051BC /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 983F07442119C9D2004133ED /* message.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = message.wav; path = ../android/app/src/main/res/raw/message.wav; sourceTree = ""; }; 9880471720650CBC00CEBFE0 /* ReactNativeTestFairy.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactNativeTestFairy.xcodeproj; path = "../node_modules/react-native-testfairy/ios/ReactNativeTestFairy.xcodeproj"; sourceTree = ""; }; 9E0B01A01DDC5DA7002B0359 /* SF-UI-Text-Light.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-UI-Text-Light.otf"; sourceTree = ""; }; 9E3AB6B21D87DA2A008846B4 /* React-Native-Webview-Bridge.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "React-Native-Webview-Bridge.xcodeproj"; path = "../node_modules/react-native-webview-bridge/ios/React-Native-Webview-Bridge.xcodeproj"; sourceTree = ""; }; @@ -613,7 +614,6 @@ EA36FD18BC2ECACF0A8B83DE /* InstabugCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = InstabugCore.framework; path = "../node_modules/instabug-reactnative/ios/InstabugCore.framework"; sourceTree = ""; }; F090E261B9854867A728CE4F /* RealmReact.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RealmReact.xcodeproj; path = "../node_modules/realm/react-native/ios/RealmReact.xcodeproj"; sourceTree = ""; }; F3548417D8DA4362B6796A54 /* RNInstabug.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNInstabug.xcodeproj; path = "../node_modules/instabug-reactnative/ios/RNInstabug.xcodeproj"; sourceTree = ""; }; - F89A8F8005874B86B63C22E3 /* RNFIRMessaging.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNFIRMessaging.xcodeproj; path = "../node_modules/react-native-fcm/ios/RNFIRMessaging.xcodeproj"; sourceTree = ""; }; F9238D6B1E5F055900C047B9 /* SF-UI-Text-Semibold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SF-UI-Text-Semibold.otf"; sourceTree = ""; }; FC1CBCFE6C906043D6CCEEE1 /* libPods-StatusImTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-StatusImTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -631,15 +631,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 475D202F20B7450D00879A77 /* libRNFirebase.a in Frameworks */, 4CA4DA1B206D105D006A98B0 /* libRNInstabug.a in Frameworks */, 98482A6F2065257B00263651 /* libReactNativeTestFairy.a in Frameworks */, C93242561FE1C68C00FE7099 /* libRCTAnimation.a in Frameworks */, 4C16DE0C1F89508700AA10DB /* JavaScriptCore.framework in Frameworks */, B2DEA0D01E49E33300FA28D6 /* libRCTHttpServer.a in Frameworks */, - 925C1F481F7B73B20063DFA0 /* FirebaseCoreDiagnostics.framework in Frameworks */, 9EE89E271E03FCB7007D3C25 /* libSplashScreen.a in Frameworks */, - 925C1F811F7B73C00063DFA0 /* FirebaseMessaging.framework in Frameworks */, - 925C1F4A1F7B73B20063DFA0 /* FirebaseNanoPB.framework in Frameworks */, B24FC7FF1DE7195F00D694FF /* MessageUI.framework in Frameworks */, B24FC7FD1DE7195700D694FF /* Social.framework in Frameworks */, 9EE89E2D1E03FD9F007D3C25 /* libimageCropPicker.a in Frameworks */, @@ -647,7 +645,6 @@ 20B6B6841D92C42600CC5C6A /* RSKImageCropper.framework in Frameworks */, CE4E31B31D8695250033ED64 /* Statusgo.framework in Frameworks */, 20AB9EC61D47CC0300E7FD9C /* libRCTStatus.a in Frameworks */, - 925C1F471F7B73B20063DFA0 /* FirebaseCore.framework in Frameworks */, 20B6B6871D92C42600CC5C6A /* QBImagePicker.framework in Frameworks */, ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */, 146834051AC3E58100842450 /* libReact.a in Frameworks */, @@ -670,10 +667,8 @@ 3E15DFEC1F6F4D7CAE088F49 /* libTcpSockets.a in Frameworks */, E0AD9E8F495A4907B65104BF /* libRCTImageResizer.a in Frameworks */, 8E55E6877F950B81C8D711C5 /* libPods-StatusIm.a in Frameworks */, - 925C1F491F7B73B20063DFA0 /* FirebaseInstanceID.framework in Frameworks */, 9EF0836B1F3B53AB00876A8F /* libReactNativeConfig.a in Frameworks */, B957A49EB0DE44D9A31CAF2D /* libRNSVG.a in Frameworks */, - 5974D2035B8B47E0946B63B6 /* libRNFIRMessaging.a in Frameworks */, 91446A820DA5E1C15C24D2A7 /* Instabug.framework in Frameworks */, 63AE4174241B852A045FAE1F /* InstabugCore.framework in Frameworks */, AB96C730942E49178F59AE6F /* libRNSecureRandom.a in Frameworks */, @@ -802,6 +797,7 @@ 1E7837547A9A40E18AD63CF3 /* Resources */ = { isa = PBXGroup; children = ( + 983F07442119C9D2004133ED /* message.wav */, 2028E0111D4275BD00227DCD /* SF */, B23B48FE1E76917B006D4535 /* RobotoMono-Medium.ttf */, 74B758FB20D7C00B003343C3 /* launch-image-universal.storyboard */, @@ -883,6 +879,22 @@ name = Products; sourceTree = ""; }; + 475D1EEE20B73EE000879A77 /* Products */ = { + isa = PBXGroup; + children = ( + 475D1EF220B73EE000879A77 /* libRNSecureRandom.a */, + ); + name = Products; + sourceTree = ""; + }; + 475D1F8E20B7413500879A77 /* Products */ = { + isa = PBXGroup; + children = ( + 475D1FC020B7413500879A77 /* libRNFirebase.a */, + ); + name = Products; + sourceTree = ""; + }; 5C1C8762251D6EF495FB2384 /* Pods */ = { isa = PBXGroup; children = ( @@ -906,6 +918,7 @@ 832341AE1AAA6A7D00B99B32 /* Libraries */ = { isa = PBXGroup; children = ( + 475D1F8D20B7413500879A77 /* RNFirebase.xcodeproj */, 9880471720650CBC00CEBFE0 /* ReactNativeTestFairy.xcodeproj */, 9EF083381F3B538A00876A8F /* ReactNativeConfig.xcodeproj */, B2DEA0A41E49E32000FA28D6 /* RCTHttpServer.xcodeproj */, @@ -934,7 +947,6 @@ 5E5A7625B76441D984EA8C0D /* RCTImageResizer.xcodeproj */, F3548417D8DA4362B6796A54 /* RNInstabug.xcodeproj */, 1E74DC52A1E449A2BA858B14 /* RNSVG.xcodeproj */, - F89A8F8005874B86B63C22E3 /* RNFIRMessaging.xcodeproj */, AF409BB755B94FB1BBA01927 /* RNSecureRandom.xcodeproj */, ); name = Libraries; @@ -978,14 +990,6 @@ name = Products; sourceTree = ""; }; - 922C4C211F4D5C3F0033C753 /* Products */ = { - isa = PBXGroup; - children = ( - 922C4C4B1F4D5C3F0033C753 /* libRNFIRMessaging.a */, - ); - name = Products; - sourceTree = ""; - }; 92925B361F571DE600203EEB /* Products */ = { isa = PBXGroup; children = ( @@ -1038,6 +1042,8 @@ A97BA941B2FB44B4B66EE6D3 /* Frameworks */ = { isa = PBXGroup; children = ( + 475D1FCD20B7415300879A77 /* libFirebaseCore.a */, + 475D1FCE20B7415300879A77 /* libFirebaseMessaging.a */, 4C16DE0B1F89508700AA10DB /* JavaScriptCore.framework */, 925C1F7F1F7B73C00063DFA0 /* FirebaseMessaging.framework */, 925C1F401F7B73B20063DFA0 /* FirebaseCore.framework */, @@ -1094,14 +1100,6 @@ name = Products; sourceTree = ""; }; - C20F3A6B20E5165A00757214 /* Products */ = { - isa = PBXGroup; - children = ( - C20F3A6F20E5165B00757214 /* libRNSecureRandom.a */, - ); - name = Products; - sourceTree = ""; - }; C90047C11FC47AF30002B8EA /* Recovered References */ = { isa = PBXGroup; children = ( @@ -1118,6 +1116,7 @@ AF2BF381BC7B4EB0887F0091 /* libRNSVG.a */, 7F752F17B1E04216B1337A72 /* libRNFIRMessaging.a */, 1464A9A9E12F45068947C28F /* libRNSecureRandom.a */, + 0A9C79F2FD464877A7CC0BC2 /* libRNFirebase.a */, ); name = "Recovered References"; sourceTree = ""; @@ -1310,8 +1309,8 @@ ProjectRef = F090E261B9854867A728CE4F /* RealmReact.xcodeproj */; }, { - ProductGroup = 922C4C211F4D5C3F0033C753 /* Products */; - ProjectRef = F89A8F8005874B86B63C22E3 /* RNFIRMessaging.xcodeproj */; + ProductGroup = 475D1F8E20B7413500879A77 /* Products */; + ProjectRef = 475D1F8D20B7413500879A77 /* RNFirebase.xcodeproj */; }, { ProductGroup = 20B7D1161D3F74CD00B70F14 /* Products */; @@ -1326,7 +1325,7 @@ ProjectRef = F3548417D8DA4362B6796A54 /* RNInstabug.xcodeproj */; }, { - ProductGroup = C20F3A6B20E5165A00757214 /* Products */; + ProductGroup = 475D1EEE20B73EE000879A77 /* Products */; ProjectRef = AF409BB755B94FB1BBA01927 /* RNSecureRandom.xcodeproj */; }, { @@ -1456,6 +1455,20 @@ remoteRef = 20B7D1281D3F74CD00B70F14 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 475D1EF220B73EE000879A77 /* libRNSecureRandom.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRNSecureRandom.a; + remoteRef = 475D1EF120B73EE000879A77 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 475D1FC020B7413500879A77 /* libRNFirebase.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRNFirebase.a; + remoteRef = 475D1FBF20B7413500879A77 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; 5537E2AA20650E640085CED4 /* libjsinspector.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; @@ -1484,13 +1497,6 @@ remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 922C4C4B1F4D5C3F0033C753 /* libRNFIRMessaging.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRNFIRMessaging.a; - remoteRef = 922C4C4A1F4D5C3F0033C753 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; 92925B681F571DE600203EEB /* libRNSVG.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; @@ -1596,13 +1602,6 @@ remoteRef = B2DEA0B01E49E32000FA28D6 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - C20F3A6F20E5165B00757214 /* libRNSecureRandom.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRNSecureRandom.a; - remoteRef = C20F3A6E20E5165B00757214 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; C90047CD1FC47AF50002B8EA /* libRCTBlob-tvOS.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; @@ -1780,6 +1779,7 @@ files = ( 9ED2F4611D9D579900B36508 /* SF-UI-Text-Bold.otf in Resources */, 9E0B01A11DDC5DA7002B0359 /* SF-UI-Text-Light.otf in Resources */, + 983F077E2119C9D2004133ED /* message.wav in Resources */, 9ED2F45E1D9D535A00B36508 /* SF-UI-Text-Regular.otf in Resources */, 74B758FC20D7C00B003343C3 /* launch-image-universal.storyboard in Resources */, 9ED2F45F1D9D535A00B36508 /* SF-UI-Text-Medium.otf in Resources */, @@ -1945,6 +1945,7 @@ "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", ); PRODUCT_BUNDLE_IDENTIFIER = im.status.ethereum; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1989,6 +1990,7 @@ "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"", + "\"$(SRCROOT)/$(TARGET_NAME)\"", ); PRODUCT_BUNDLE_IDENTIFIER = im.status.ethereum; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2034,10 +2036,12 @@ "$(SRCROOT)/../node_modules/react-native-splash-screen/ios", "$(SRCROOT)/../node_modules/react-native-config/ios/**", "$(SRCROOT)/../node_modules/react-native-svg/ios/**", - "$(SRCROOT)/../node_modules/react-native-fcm/ios", "$(SRCROOT)/../node_modules/react-native-testfairy/ios", "$(SRCROOT)/../node_modules/react-native-securerandom/ios", "$(SRCROOT)/../node_modules/react-native/Libraries/LinkingIOS", + "$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase", + "$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase/messaging", + "$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase/notifications", ); INFOPLIST_FILE = StatusIm/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 11.0; @@ -2096,10 +2100,12 @@ "$(SRCROOT)/../node_modules/react-native-splash-screen/ios", "$(SRCROOT)/../node_modules/react-native-config/ios/**", "$(SRCROOT)/../node_modules/react-native-svg/ios/**", - "$(SRCROOT)/../node_modules/react-native-fcm/ios", "$(SRCROOT)/../node_modules/react-native-testfairy/ios", "$(SRCROOT)/../node_modules/react-native-securerandom/ios", "$(SRCROOT)/../node_modules/react-native/Libraries/LinkingIOS", + "$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase", + "$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase/messaging", + "$(SRCROOT)/../node_modules/react-native-firebase/ios/RNFirebase/notifications", ); INFOPLIST_FILE = StatusIm/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 11.0; diff --git a/ios/StatusIm/AppDelegate.h b/ios/StatusIm/AppDelegate.h index 14ef57dbd2..a9654d5e01 100644 --- a/ios/StatusIm/AppDelegate.h +++ b/ios/StatusIm/AppDelegate.h @@ -9,9 +9,7 @@ #import -@import UserNotifications; - -@interface AppDelegate : UIResponder +@interface AppDelegate : UIResponder @property (nonatomic, strong) UIWindow *window; diff --git a/ios/StatusIm/AppDelegate.m b/ios/StatusIm/AppDelegate.m index afaed3a520..d0aa5709dd 100644 --- a/ios/StatusIm/AppDelegate.m +++ b/ios/StatusIm/AppDelegate.m @@ -16,8 +16,10 @@ #import "RCTRootView.h" #import "SplashScreen.h" #import "TestFairy.h" -#import "RNFIRMessaging.h" #import "RCTLinkingManager.h" +#import +#import "RNFirebaseNotifications.h" +#import "RNFirebaseMessaging.h" @implementation AppDelegate @@ -64,6 +66,11 @@ RCTLogFunction RCTTestFairyLogFunction = ^( signal(SIGPIPE, SIG_IGN); NSURL *jsCodeLocation; + [FIRApp configure]; + [RNFirebaseNotifications configure]; + [application registerForRemoteNotifications]; + + /* Set logging level from React Native */ NSString *logLevel = [ReactNativeConfig envFor:@"LOG_LEVEL"]; if([logLevel isEqualToString:@"error"]){ @@ -95,29 +102,20 @@ RCTLogFunction RCTTestFairyLogFunction = ^( [self.window makeKeyAndVisible]; [SplashScreen show]; - [FIRApp configure]; - [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self]; - return YES; } - -- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler -{ -[RNFIRMessaging willPresentNotification:notification withCompletionHandler:completionHandler]; +- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { + [[RNFirebaseNotifications instance] didReceiveLocalNotification:notification]; } -- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler -{ -[RNFIRMessaging didReceiveNotificationResponse:response withCompletionHandler:completionHandler]; +- (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo + fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{ + [[RNFirebaseNotifications instance] didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler]; } --(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { -[RNFIRMessaging didReceiveLocalNotification:notification]; -} - -- (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{ -[RNFIRMessaging didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler]; +- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { + [[RNFirebaseMessaging instance] didRegisterUserNotificationSettings:notificationSettings]; } - (BOOL)application:(UIApplication *)application diff --git a/mobile_files/package-lock.json b/mobile_files/package-lock.json index e82247932e..1e7ed84fff 100644 --- a/mobile_files/package-lock.json +++ b/mobile_files/package-lock.json @@ -5547,6 +5547,69 @@ "mimic-fn": "1.2.0" } }, + "opencollective": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/opencollective/-/opencollective-1.0.3.tgz", + "integrity": "sha1-ruY3K8KBRFg2kMPKja7PwSDdDvE=", + "requires": { + "babel-polyfill": "6.23.0", + "chalk": "1.1.3", + "inquirer": "3.0.6", + "minimist": "1.2.0", + "node-fetch": "1.6.3", + "opn": "4.0.2" + }, + "dependencies": { + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=" + }, + "inquirer": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.0.6.tgz", + "integrity": "sha1-4EqqnQW3o8ubD0B9BDdfBEcZA0c=", + "requires": { + "ansi-escapes": "1.4.0", + "chalk": "1.1.3", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.2.0", + "figures": "2.0.0", + "lodash": "4.17.10", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx": "4.1.0", + "string-width": "2.1.1", + "strip-ansi": "3.0.1", + "through": "2.3.8" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "node-fetch": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz", + "integrity": "sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ=", + "requires": { + "encoding": "0.1.12", + "is-stream": "1.1.0" + } + }, + "opn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", + "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", + "requires": { + "object-assign": "4.1.1", + "pinkie-promise": "2.0.1" + } + } + } + }, "opn": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/opn/-/opn-3.0.3.tgz", @@ -5832,6 +5895,11 @@ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" }, + "postinstall-build": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/postinstall-build/-/postinstall-build-5.0.1.tgz", + "integrity": "sha1-uRepB5smF42aJK9aXNjLSpkdEbk=" + }, "preserve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", @@ -6234,16 +6302,33 @@ "resolved": "https://registry.npmjs.org/react-native-dialogs/-/react-native-dialogs-0.0.20.tgz", "integrity": "sha512-HeoU9d7wWUUAtxjcIJLaeIs/eYS2ZHTNh3kboeCKngLvfvgptd/7vZXwXdQ+xeOEek+cm95kDfMJQd2xnb+4wA==" }, - "react-native-fcm": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/react-native-fcm/-/react-native-fcm-10.0.3.tgz", - "integrity": "sha1-HcU47YifkLelvB0FMMxRbmmwnow=" - }, "react-native-fetch-polyfill": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/react-native-fetch-polyfill/-/react-native-fetch-polyfill-1.1.2.tgz", "integrity": "sha1-JWtaCr14zEmS96fPglQ9ovISSnM=" }, + "react-native-firebase": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/react-native-firebase/-/react-native-firebase-4.2.0.tgz", + "integrity": "sha512-HGmvsToYD9qrVoe0u/kXSNG6lHvPah9bbC1Rvt/L5669kHs7oSufS9SM0QzDpEw8QEstXCrB/yg+57VEsUUtFw==", + "requires": { + "opencollective": "1.0.3", + "postinstall-build": "5.0.1", + "prop-types": "15.6.1" + }, + "dependencies": { + "prop-types": { + "version": "15.6.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.1.tgz", + "integrity": "sha512-4ec7bY1Y66LymSUOH/zARVYObB23AT2h8cf6e/O6ZALB/N0sqZFEx7rq6EYPX2MkOdKORuooI/H5k9TlR4q7kQ==", + "requires": { + "fbjs": "0.8.16", + "loose-envify": "1.3.1", + "object-assign": "4.1.1" + } + } + } + }, "react-native-fs": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/react-native-fs/-/react-native-fs-2.8.1.tgz", @@ -6813,6 +6898,11 @@ "is-promise": "2.1.0" } }, + "rx": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", + "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=" + }, "rx-lite": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", diff --git a/mobile_files/package.json b/mobile_files/package.json index c197a7d435..6656f1abda 100644 --- a/mobile_files/package.json +++ b/mobile_files/package.json @@ -38,8 +38,8 @@ "react-native-config": "0.9.0", "react-native-crypto": "2.1.1", "react-native-dialogs": "0.0.20", - "react-native-fcm": "10.0.3", "react-native-fetch-polyfill": "1.1.2", + "react-native-firebase": "4.2.0", "react-native-fs": "2.8.1", "react-native-http-bridge": "https://github.com/status-im/react-native-http-bridge.git", "react-native-i18n": "2.0.9", diff --git a/react-native/src/desktop/status_im/react_native/js_dependencies.cljs b/react-native/src/desktop/status_im/react_native/js_dependencies.cljs index 47ec56f74b..c9598a680f 100644 --- a/react-native/src/desktop/status_im/react_native/js_dependencies.cljs +++ b/react-native/src/desktop/status_im/react_native/js_dependencies.cljs @@ -12,6 +12,7 @@ (def EventEmmiter (js/require "react-native/Libraries/vendor/emitter/EventEmitter")) (def fetch (.-default (js/require "react-native-fetch-polyfill"))) (def i18n (js/require "react-native-i18n")) +(def react-native-firebase (js/require "react-native-firebase")) (def camera #js {:constants {:Aspect "Portrait"}}) (def dialogs #js {}) (def dismiss-keyboard #js {}) @@ -20,8 +21,6 @@ (def instabug #js {:IBGLog ( fn [])}) (def nfc #js {}) (def svg #js {}) -(def react-native-fcm #js {:default #js {:getFCMToken (fn []) - :requestPermissions (fn [])}}) (def snoopy #js {}) (def snoopy-filter #js {}) (def snoopy-bars #js {}) diff --git a/react-native/src/mobile/status_im/react_native/js_dependencies.cljs b/react-native/src/mobile/status_im/react_native/js_dependencies.cljs index c37d1977d9..fe20aacea9 100644 --- a/react-native/src/mobile/status_im/react_native/js_dependencies.cljs +++ b/react-native/src/mobile/status_im/react_native/js_dependencies.cljs @@ -19,7 +19,7 @@ (def image-resizer (js/require "react-native-image-resizer")) (def instabug (js/require "instabug-reactnative")) (def svg (js/require "react-native-svg")) -(def react-native-fcm (js/require "react-native-fcm")) +(def react-native-firebase (js/require "react-native-firebase")) (def snoopy (js/require "rn-snoopy")) (def snoopy-filter (js/require "rn-snoopy/stream/filter")) (def snoopy-bars (js/require "rn-snoopy/stream/bars")) diff --git a/src/status_im/android/core.cljs b/src/status_im/android/core.cljs index 42bf21ab09..b7f6b62a22 100644 --- a/src/status_im/android/core.cljs +++ b/src/status_im/android/core.cljs @@ -60,9 +60,8 @@ (.addEventListener react/app-state "change" app-state-change-handler)) :component-did-mount (fn [] - (notifications/on-refresh-fcm-token) ;; TODO(oskarth): Background click_action handler - (notifications/on-notification)) + (notifications/init)) :component-will-unmount (fn [] (.stop react/http-bridge) diff --git a/src/status_im/chat/models/message.cljs b/src/status_im/chat/models/message.cljs index 76549f07f8..921046cc6b 100644 --- a/src/status_im/chat/models/message.cljs +++ b/src/status_im/chat/models/message.cljs @@ -1,7 +1,9 @@ (ns status-im.chat.models.message (:require [re-frame.core :as re-frame] [status-im.constants :as constants] + [status-im.i18n :as i18n] [status-im.utils.core :as utils] + [status-im.utils.config :as config] [status-im.utils.ethereum.core :as ethereum] [status-im.utils.datetime :as time] [status-im.chat.models :as chat-model] @@ -10,6 +12,7 @@ [status-im.utils.clocks :as utils.clocks] [status-im.utils.handlers-macro :as handlers-macro] [status-im.utils.money :as money] + [status-im.utils.notifications :as notifications] [status-im.transport.utils :as transport.utils] [status-im.transport.message.core :as transport] [status-im.transport.message.v1.protocol :as protocol] @@ -132,6 +135,18 @@ (= constants/content-type-command-request content-type) (assoc :content-type constants/content-type-command))) +(defn- display-notification [chat-id cofx] + (when config/in-app-notifications-enabled? + (let [view-id (get-in cofx [:db :view-id]) + from (get-in cofx [:db :current-public-key]) + current-chat-id (get-in cofx [:db :current-chat-id])] + (when-not (and (= :chat view-id) + (= current-chat-id chat-id)) + {:display-notification-fx {:title (i18n/label :notifications-new-message-title) + :body (i18n/label :notifications-new-message-body) + :to chat-id + :from from}})))) + (defn- add-received-message [batch? {:keys [from message-id chat-id content content-type clock-value js-obj] :as raw-message} @@ -157,6 +172,7 @@ current-chat? :seen :else :received)) (commands-receiving/receive message) + (display-notification chat-id) (send-message-seen chat-id message-id (and (not public?) current-chat? (not (chat-model/bot-only-chat? db chat-id)) @@ -258,8 +274,11 @@ (defn send-push-notification [fcm-token status cofx] (when (and fcm-token (= status :sent)) - {:send-notification {:message "message" - :payload {:title "Status" :body "You have a new message"} + {:send-notification {:message (js/JSON.stringify #js {:from (get-in cofx [:db :current-public-key]) + :to (get-in cofx [:db :current-chat-id])}) + :payload {:title (i18n/label :notifications-new-message-title) + :body (i18n/label :notifications-new-message-body) + :sound notifications/sound-name} :tokens [fcm-token]}})) (defn update-message-status [{:keys [chat-id message-id from]} status {:keys [db]}] diff --git a/src/status_im/ios/core.cljs b/src/status_im/ios/core.cljs index 6a96ba0862..ee6a5241ae 100644 --- a/src/status_im/ios/core.cljs +++ b/src/status_im/ios/core.cljs @@ -36,8 +36,7 @@ (.addEventListener react/app-state "change" app-state-change-handler)) :component-did-mount (fn [] - (notifications/on-refresh-fcm-token) - (notifications/on-notification)) + (notifications/init)) :component-will-unmount (fn [] (.stop react/http-bridge) diff --git a/src/status_im/translations/en.cljs b/src/status_im/translations/en.cljs index e7e473bacf..3e2c4caf66 100644 --- a/src/status_im/translations/en.cljs +++ b/src/status_im/translations/en.cljs @@ -108,6 +108,10 @@ :delete-message "Delete message" :sent-at "Sent at" + ;;notifications + :notifications-new-message-body "You have new message" + :notifications-new-message-title "Status" + ;;datetime :datetime-ago-format "{{number}} {{time-intervals}} {{ago}}" :datetime-second {:one "second" diff --git a/src/status_im/ui/screens/accounts/login/models.cljs b/src/status_im/ui/screens/accounts/login/models.cljs index 49718918ff..1f19d102e6 100644 --- a/src/status_im/ui/screens/accounts/login/models.cljs +++ b/src/status_im/ui/screens/accounts/login/models.cljs @@ -6,6 +6,7 @@ [status-im.native-module.core :as status] [status-im.utils.config :as config] [status-im.utils.keychain.core :as keychain] + [status-im.utils.notifications :as notifications] [status-im.utils.universal-links.core :as universal-links])) ;;;; FX @@ -131,4 +132,5 @@ :dispatch [:initialize-account address (when (not= view-id :create-account) [[:navigate-to-clean :home] - (universal-links/stored-url-event cofx)])]}) + (universal-links/stored-url-event cofx) + (notifications/stored-event address cofx)])]}) diff --git a/src/status_im/ui/screens/db.cljs b/src/status_im/ui/screens/db.cljs index 53d8d413af..a533b97286 100644 --- a/src/status_im/ui/screens/db.cljs +++ b/src/status_im/ui/screens/db.cljs @@ -53,7 +53,9 @@ :chat/spam-messages-frequency 0 :tooltips {} :desktop/desktop {:tab-view-id :home} - :dimensions/window (dimensions/window)}) + :dimensions/window (dimensions/window) + :push-notifications/stored {} + :push-notifications/initial? false}) ;;;;GLOBAL @@ -161,6 +163,12 @@ ;; DIMENSIONS (spec/def :dimensions/window map?) +;; PUSH NOTIFICATIONS + +(spec/def :push-notifications/stored (spec/nilable map?)) +; Shows that push notification used to start the application is processed +(spec/def :push-notifications/initial? (spec/nilable boolean?)) + (spec/def ::db (allowed-keys :opt [:contacts/contacts @@ -199,6 +207,8 @@ :inbox/current-id :inbox/fetching? :universal-links/url + :push-notifications/stored + :push-notifications/initial? :browser/browsers :browser/options :new/open-dapp diff --git a/src/status_im/ui/screens/events.cljs b/src/status_im/ui/screens/events.cljs index 34f0c132ec..69483030d7 100644 --- a/src/status_im/ui/screens/events.cljs +++ b/src/status_im/ui/screens/events.cljs @@ -213,20 +213,22 @@ :on-accept handle-reset-data}) (defn initialize-views [{{:accounts/keys [accounts] :as db} :db}] - {:db (if (empty? accounts) - (assoc db :view-id :intro :navigation-stack (list :intro)) - (let [{:keys [address photo-path name]} (first (sort-by :last-sign-in > (vals accounts)))] - (-> db - (assoc :view-id :login - :navigation-stack (list :login)) - (update :accounts/login assoc - :address address - :photo-path photo-path - :name name))))}) + {:db (if (empty? accounts) + (assoc db :view-id :intro :navigation-stack (list :intro)) + (let [{:keys [address photo-path name]} (first (sort-by :last-sign-in > (vals accounts)))] + (-> db + (assoc :view-id :login + :navigation-stack (list :login)) + (update :accounts/login assoc + :address address + :photo-path photo-path + :name name)))) + :handle-initial-push-notification-fx db}) (defn initialize-db "Initialize db to the initial state" [{{:universal-links/keys [url] + :push-notifications/keys [initial?] :keys [status-module-initialized? status-node-started? network-status network peers-count peers-summary device-UUID] :or {network (get app-db :network)}} :db}] @@ -239,6 +241,7 @@ :status-node-started? status-node-started? :network network :universal-links/url url + :push-notifications/initial? initial? :device-UUID device-UUID)}) ;; Entrypoint, fetches the key from the keychain and initialize the app @@ -292,7 +295,8 @@ :initialize-account-db (fn [{:keys [accounts/accounts accounts/create contacts/contacts networks/networks network network-status peers-count peers-summary view-id navigation-stack - status-module-initialized? status-node-started? device-UUID] + status-module-initialized? status-node-started? device-UUID + push-notifications/initial?] :or [network (get app-db :network)]} [_ address]] (let [console-contact (get contacts constants/console-chat-id) current-account (accounts address) @@ -310,6 +314,7 @@ :network-status network-status :network network :chain (ethereum/network->chain-name account-network) + :push-notifications/initial? initial? :peers-summary peers-summary :peers-count peers-count :device-UUID device-UUID) diff --git a/src/status_im/utils/config.cljs b/src/status_im/utils/config.cljs index dff557e200..a8e23ab66c 100644 --- a/src/status_im/utils/config.cljs +++ b/src/status_im/utils/config.cljs @@ -43,3 +43,4 @@ (def group-chats-enabled? (enabled? (get-config :GROUP_CHATS_ENABLED))) (def spam-button-detection-enabled? (enabled? (get-config :SPAM_BUTTON_DETECTION_ENABLED "0"))) (def mainnet-warning-enabled? (enabled? (get-config :MAINNET_WARNING_ENABLED 0))) +(def in-app-notifications-enabled? (enabled? (get-config :IN_APP_NOTIFICATIONS_ENABLED 0))) diff --git a/src/status_im/utils/notifications.cljs b/src/status_im/utils/notifications.cljs index 24139ed77f..b9ec989bf4 100644 --- a/src/status_im/utils/notifications.cljs +++ b/src/status_im/utils/notifications.cljs @@ -1,10 +1,10 @@ (ns status-im.utils.notifications (:require [goog.object :as object] - [re-frame.core :as re-frame :refer [dispatch reg-fx]] + [re-frame.core :as re-frame] + [status-im.utils.handlers-macro :as handlers-macro] [status-im.utils.handlers :as handlers] [status-im.react-native.js-dependencies :as rn] - [status-im.utils.config :as config] - [status-im.utils.utils :as utils] + [status-im.utils.platform :as platform] [status-im.ui.components.react :refer [copy-to-clipboard]] [taoensso.timbre :as log] [status-im.utils.platform :as platform])) @@ -20,48 +20,167 @@ (handlers/register-handler-fx :request-notifications-granted (fn [_ _] - (re-frame.core/dispatch [:show-mainnet-is-default-alert]))) + (re-frame/dispatch [:show-mainnet-is-default-alert]))) (handlers/register-handler-fx :request-notifications-denied (fn [_ _] - (re-frame.core/dispatch [:show-mainnet-is-default-alert]))) + (re-frame/dispatch [:show-mainnet-is-default-alert]))) + +(def firebase (object/get rn/react-native-firebase "default")) ;; NOTE: Only need to explicitly request permissions on iOS. (defn request-permissions [] (if platform/desktop? - (dispatch [:request-notifications-granted {}]) - (-> (.requestPermissions (.-default rn/react-native-fcm)) + (re-frame/dispatch [:request-notifications-granted {}]) + (-> (.requestPermission (.messaging firebase)) (.then (fn [_] (log/debug "notifications-granted") - (dispatch [:request-notifications-granted {}])) + (re-frame/dispatch [:request-notifications-granted {}])) (fn [_] (log/debug "notifications-denied") - (dispatch [:request-notifications-denied {}])))))) + (re-frame/dispatch [:request-notifications-denied {}])))))) (defn get-fcm-token [] - (-> (.getFCMToken (object/get rn/react-native-fcm "default")) + (-> (.getToken (.messaging firebase)) (.then (fn [x] (log/debug "get-fcm-token: " x) - (dispatch [:update-fcm-token x]))))) + (re-frame/dispatch [:update-fcm-token x]))))) (defn on-refresh-fcm-token [] - (.on (.-default rn/react-native-fcm) - (.-RefreshToken (.-FCMEvent rn/react-native-fcm)) - (fn [x] - (log/debug "on-refresh-fcm-token: " x) - (dispatch [:update-fcm-token x])))) + (.onTokenRefresh (.messaging firebase) + (fn [x] + (log/debug "on-refresh-fcm-token: " x) + (re-frame/dispatch [:update-fcm-token x])))) ;; TODO(oskarth): Only called in background on iOS right now. ;; NOTE(oskarth): Hardcoded data keys :sum and :msg in status-go right now. (defn on-notification [] - (.on (.-default rn/react-native-fcm) - (.-Notification (.-FCMEvent rn/react-native-fcm)) - (fn [event-js] - (let [event (js->clj event-js :keywordize-keys true) - data (select-keys event [:sum :msg]) - aps (:aps event)] - (log/debug "on-notification event: " (pr-str event)) - (log/debug "on-notification aps: " (pr-str aps)) - (log/debug "on-notification data: " (pr-str data)))))) + (.onNotification (.notifications firebase) + (fn [event-js] + (let [event (js->clj event-js :keywordize-keys true) + data (select-keys event [:sum :msg]) + aps (:aps event)] + (log/debug "on-notification event: " (pr-str event)) + (log/debug "on-notification aps: " (pr-str aps)) + (log/debug "on-notification data: " (pr-str data)))))) + +(def channel-id "status-im") +(def channel-name "Status") +(def sound-name "message.wav") +(def group-id "im.status.ethereum.MESSAGE") +(def icon "ic_stat_status_notification") + +(defn create-notification-channel [] + (let [channel (firebase.notifications.Android.Channel. channel-id + channel-name + firebase.notifications.Android.Importance.Max)] + (.setSound channel sound-name) + (.setShowBadge channel true) + (.enableVibration channel true) + (.. firebase + notifications + -android + (createChannel channel) + (then #(log/debug "Notification channel created:" channel-id) + #(log/error "Notification channel creation error:" channel-id %))))) + +(defn store-event [{:keys [from to]} {:keys [db] :as cofx}] + (let [{:keys [address photo-path name]} (->> (get-in cofx [:db :accounts/accounts]) + vals + (filter #(= (:public-key %) to)) + first)] + (when address + {:db (assoc-in db [:push-notifications/stored to] from) + :dispatch [:open-login address photo-path name]}))) + +(defn process-initial-push-notification [{:keys [initial?]} {:keys [db]}] + (when initial? + {:db (assoc db :push-notifications/initial? true)})) + +(defn process-push-notification [{:keys [from to] :as event} {:keys [db] :as cofx}] + (let [current-public-key (get-in cofx [:db :current-public-key])] + (if current-public-key + (when (= to current-public-key) + {:db (update db :push-notifications/stored dissoc to) + :dispatch [:navigate-to-chat from]}) + (store-event event cofx)))) + +(defn handle-push-notification [cofx [_ event]] + (handlers-macro/merge-fx cofx + (process-initial-push-notification event) + (process-push-notification event))) + +(defn stored-event [address cofx] + (let [to (get-in cofx [:db :accounts/accounts address :public-key]) + from (get-in cofx [:db :push-notifications/stored to])] + (when from + [:handle-push-notification {:from from + :to to}]))) + +(defn parse-notification-payload [s] + (try + (js/JSON.parse s) + (catch :default _ + #js {}))) + +(defn handle-notification-event [event {:keys [initial?]}] + (let [msg (object/get (.. event -notification -data) "msg") + data (parse-notification-payload msg) + from (object/get data "from") + to (object/get data "to")] + (log/debug "on notification" (pr-str msg)) + (when (and from to) + (re-frame/dispatch [:handle-push-notification {:from from + :to to + :initial? initial?}])))) + +(defn on-notification-opened [] + (.. firebase + notifications + (onNotificationOpened handle-notification-event))) + +(def notification (firebase.notifications.Notification.)) + +;; API reference https://rnfirebase.io/docs/v4.2.x/notifications/reference/AndroidNotification +(defn display-notification [{:keys [title body from to]}] + (.. notification + (setTitle title) + (setBody body) + (setData (js/JSON.stringify #js {:from from + :to to})) + (setSound sound-name) + (-android.setChannelId channel-id) + (-android.setAutoCancel true) + (-android.setPriority firebase.notifications.Android.Priority.Max) + (-android.setGroup group-id) + (-android.setGroupSummary true) + (-android.setSmallIcon icon)) + (.. firebase + notifications + (displayNotification notification) + (then #(log/debug "Display Notification" title body)) + (then #(log/debug "Display Notification error" title body)))) + +(re-frame/reg-fx :display-notification-fx display-notification) + +(handlers/register-handler-fx :handle-push-notification handle-push-notification) + +(re-frame/reg-fx + :handle-initial-push-notification-fx + (fn [{:keys [push-notifications/initial?]}] + (when-not initial? + (.. firebase + notifications + getInitialNotification + (then (fn [event] + (when event + (handle-notification-event event {:initial? true})))))))) + +(defn init [] + (on-refresh-fcm-token) + (on-notification) + (on-notification-opened) + (when platform/android? + (create-notification-channel))) diff --git a/test/cljs/status_im/react_native/js_dependencies.cljs b/test/cljs/status_im/react_native/js_dependencies.cljs index 30ba09cf02..3f5b59f0e9 100644 --- a/test/cljs/status_im/react_native/js_dependencies.cljs +++ b/test/cljs/status_im/react_native/js_dependencies.cljs @@ -29,7 +29,9 @@ (def vector-icons #js {:default #js {}}) (def webview-bridge #js {:default #js {}}) (def svg #js {:default #js {}}) -(def react-native-fcm #js {:default #js {}}) + +(defrecord Notification []) +(def react-native-firebase #js {:default #js {:notifications #js {:Notification Notification}}}) (def snoopy #js {:default #js {}}) (def snoopy-filter #js {:default #js {}}) diff --git a/test/cljs/status_im/test/utils/notifications.cljs b/test/cljs/status_im/test/utils/notifications.cljs new file mode 100644 index 0000000000..bdbcbcc5eb --- /dev/null +++ b/test/cljs/status_im/test/utils/notifications.cljs @@ -0,0 +1,37 @@ +(ns status-im.test.utils.notifications + (:require [cljs.test :refer-macros [deftest is testing]] + [status-im.utils.notifications :as notifications])) + +(deftest test-handle-push-notification + (testing "user's signed in" + (is (= {:db {:current-public-key "0x04d2e59a7501a7bc5bc8bf973a0ab95d06225e2b0f53d5f6be719d857c579bdc1b809bfbe0e8393343f9a5b63a9a90a1a58329c6d1c286d6929f01aaa5472ca9c2" + :push-notifications/stored {}} + :dispatch [:navigate-to-chat "0x045db1fdb16c4721ddf32e892c5156d9c7a7445482b84ccd41131eb7970f9d623629d86763c5c2a542ae372815125c27eb73535d583d3285bdbfa16ba37f42e2de"]} + (notifications/handle-push-notification {:db {:push-notifications/stored {} + :current-public-key "0x04d2e59a7501a7bc5bc8bf973a0ab95d06225e2b0f53d5f6be719d857c579bdc1b809bfbe0e8393343f9a5b63a9a90a1a58329c6d1c286d6929f01aaa5472ca9c2"}} + [:push-notification-opened {:from "0x045db1fdb16c4721ddf32e892c5156d9c7a7445482b84ccd41131eb7970f9d623629d86763c5c2a542ae372815125c27eb73535d583d3285bdbfa16ba37f42e2de" + :to "0x04d2e59a7501a7bc5bc8bf973a0ab95d06225e2b0f53d5f6be719d857c579bdc1b809bfbe0e8393343f9a5b63a9a90a1a58329c6d1c286d6929f01aaa5472ca9c2"}])))) + (testing "user's signed in into another account" + (is (= {} + (notifications/handle-push-notification {:db {:current-public-key "0x04bc8bf4a91ab726bd98f2c54b3036caacaeea527867945ab839e9ad4e62696856d7f7fa485f68304de357e38a1553eac5592706a16fcf71fd821bbd6c796f9ab3"}} + [:push-notification-opened {:from "0x045db1fdb16c4721ddf32e892c5156d9c7a7445482b84ccd41131eb7970f9d623629d86763c5c2a542ae372815125c27eb73535d583d3285bdbfa16ba37f42e2de" + :to "0x04d2e59a7501a7bc5bc8bf973a0ab95d06225e2b0f53d5f6be719d857c579bdc1b809bfbe0e8393343f9a5b63a9a90a1a58329c6d1c286d6929f01aaa5472ca9c2"}])))) + (testing "user's not signed in" + (is (= {:db {:accounts/accounts {"bd36cd64e2621b054a3b7464ff1b3c4c304880e7" {:address "bd36cd64e2621b054a3b7464ff1b3c4c304880e7" + :photo-path "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAADAFBMVEX" + :name "Bob" + :public-key "0x04d2e59a7501a7bc5bc8bf973a0ab95d06225e2b0f53d5f6be719d857c579bdc1b809bfbe0e8393343f9a5b63a9a90a1a58329c6d1c286d6929f01aaa5472ca9c2"}} + :current-public-key nil + :push-notifications/initial? true + :push-notifications/stored {"0x04d2e59a7501a7bc5bc8bf973a0ab95d06225e2b0f53d5f6be719d857c579bdc1b809bfbe0e8393343f9a5b63a9a90a1a58329c6d1c286d6929f01aaa5472ca9c2" + "0x045db1fdb16c4721ddf32e892c5156d9c7a7445482b84ccd41131eb7970f9d623629d86763c5c2a542ae372815125c27eb73535d583d3285bdbfa16ba37f42e2de"}} + :dispatch [:open-login "bd36cd64e2621b054a3b7464ff1b3c4c304880e7" "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAADAFBMVEX" "Bob"]} + (notifications/handle-push-notification {:db {:accounts/accounts {"bd36cd64e2621b054a3b7464ff1b3c4c304880e7" {:address "bd36cd64e2621b054a3b7464ff1b3c4c304880e7" + :photo-path "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAADAFBMVEX" + :name "Bob" + :public-key "0x04d2e59a7501a7bc5bc8bf973a0ab95d06225e2b0f53d5f6be719d857c579bdc1b809bfbe0e8393343f9a5b63a9a90a1a58329c6d1c286d6929f01aaa5472ca9c2"}} + :current-public-key nil + :push-notifications/stored {}}} + [:push-notification-opened {:from "0x045db1fdb16c4721ddf32e892c5156d9c7a7445482b84ccd41131eb7970f9d623629d86763c5c2a542ae372815125c27eb73535d583d3285bdbfa16ba37f42e2de" + :to "0x04d2e59a7501a7bc5bc8bf973a0ab95d06225e2b0f53d5f6be719d857c579bdc1b809bfbe0e8393343f9a5b63a9a90a1a58329c6d1c286d6929f01aaa5472ca9c2" + :initial? true}])))))