Skip to content

Commit 48e14db

Browse files
committed
ios deps: Use PushNotificationIOS from react-native-community, not RN core.
In a recent commit, we asked RN's PushNotificationIOS to take responsibilities that were previously taken by wix/react-native-notifications, and removed the Wix library. Now, we account for the fact that PushNotificationsIOS from RN is deprecated [1] and asks us to use @react-native-community/push-notification-ios instead. So, do. These were my steps: 1. Use the setup instructions for `PushNotificationIOS` [1] from RN v0.60 to tear it down. 2. Follow the setup instructions for @react-native-community/push-notification-ios at the latest, v1.5.0 [2]. The native code closely matches what was there before, which makes sense. There are a few additions, and notes on old iOS APIs. 3. Follow the simple "Migrating..." instructions [3] that say you just have to change the imports; no call site changes are necessary. 4. Change a few comments that refer to details of the directory structure or implementation of the library. 5. Test thoroughly, as in the previous commit, and observe the same results. [1]: https://reactnative.dev/docs/0.60/pushnotificationios [2]: https://github.com/react-native-community/push-notification-ios/blob/v1.5.0/README.md [3]: https://github.com/react-native-community/push-notification-ios/blob/v1.5.0/README.md#migrating-from-the-core-react-native-module Fixes: #4115
1 parent 5e6429c commit 48e14db

File tree

10 files changed

+77
-64
lines changed

10 files changed

+77
-64
lines changed

ios/Podfile

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,6 @@ target 'ZulipMobile' do
7474
pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
7575
pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
7676
pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
77-
# This is deprecated upstream; removing it is #4115. See
78-
# https://reactnative.dev/docs/pushnotificationios.
79-
pod 'React-RCTPushNotification', :path => '../node_modules/react-native/Libraries/PushNotificationIOS'
8077
pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon"
8178
pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon"
8279
pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga', :modular_headers => true

ios/Podfile.lock

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -190,14 +190,6 @@ PODS:
190190
- React-jsi (= 0.61.5)
191191
- React-jsiexecutor (= 0.61.5)
192192
- Yoga
193-
- React-Core/RCTPushNotificationHeaders (0.61.5):
194-
- Folly (= 2018.10.22.00)
195-
- glog
196-
- React-Core/Default
197-
- React-cxxreact (= 0.61.5)
198-
- React-jsi (= 0.61.5)
199-
- React-jsiexecutor (= 0.61.5)
200-
- Yoga
201193
- React-Core/RCTSettingsHeaders (0.61.5):
202194
- Folly (= 2018.10.22.00)
203195
- glog
@@ -294,8 +286,6 @@ PODS:
294286
- React-Core/RCTLinkingHeaders (= 0.61.5)
295287
- React-RCTNetwork (0.61.5):
296288
- React-Core/RCTNetworkHeaders (= 0.61.5)
297-
- React-RCTPushNotification (0.61.5):
298-
- React-Core/RCTPushNotificationHeaders (= 0.61.5)
299289
- React-RCTSettings (0.61.5):
300290
- React-Core/RCTSettingsHeaders (= 0.61.5)
301291
- React-RCTText (0.61.5):
@@ -319,6 +309,8 @@ PODS:
319309
- React-Core
320310
- RNCAsyncStorage (1.6.3):
321311
- React
312+
- RNCPushNotificationIOS (1.2.2):
313+
- React
322314
- RNDeviceInfo (0.21.5):
323315
- React
324316
- RNSentry (1.6.3):
@@ -413,14 +405,14 @@ DEPENDENCIES:
413405
- React-RCTImage (from `../node_modules/react-native/Libraries/Image`)
414406
- React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`)
415407
- React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`)
416-
- React-RCTPushNotification (from `../node_modules/react-native/Libraries/PushNotificationIOS`)
417408
- React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
418409
- React-RCTText (from `../node_modules/react-native/Libraries/Text`)
419410
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
420411
- ReactCommon/jscallinvoker (from `../node_modules/react-native/ReactCommon`)
421412
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
422413
- rn-fetch-blob (from `../node_modules/rn-fetch-blob`)
423414
- "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)"
415+
- "RNCPushNotificationIOS (from `../node_modules/@react-native-community/push-notification-ios`)"
424416
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
425417
- "RNSentry (from `../node_modules/@sentry/react-native`)"
426418
- RNSound (from `../node_modules/react-native-sound`)
@@ -528,8 +520,6 @@ EXTERNAL SOURCES:
528520
:path: "../node_modules/react-native/Libraries/LinkingIOS"
529521
React-RCTNetwork:
530522
:path: "../node_modules/react-native/Libraries/Network"
531-
React-RCTPushNotification:
532-
:path: "../node_modules/react-native/Libraries/PushNotificationIOS"
533523
React-RCTSettings:
534524
:path: "../node_modules/react-native/Libraries/Settings"
535525
React-RCTText:
@@ -542,6 +532,8 @@ EXTERNAL SOURCES:
542532
:path: "../node_modules/rn-fetch-blob"
543533
RNCAsyncStorage:
544534
:path: "../node_modules/@react-native-community/async-storage"
535+
RNCPushNotificationIOS:
536+
:path: "../node_modules/@react-native-community/push-notification-ios"
545537
RNDeviceInfo:
546538
:path: "../node_modules/react-native-device-info"
547539
RNSentry:
@@ -626,13 +618,13 @@ SPEC CHECKSUMS:
626618
React-RCTImage: 6b8e8df449eb7c814c99a92d6b52de6fe39dea4e
627619
React-RCTLinking: 121bb231c7503cf9094f4d8461b96a130fabf4a5
628620
React-RCTNetwork: fb353640aafcee84ca8b78957297bd395f065c9a
629-
React-RCTPushNotification: 6d0c0cd88a40465677e07a614f65ea88c1c3de24
630621
React-RCTSettings: 8db258ea2a5efee381fcf7a6d5044e2f8b68b640
631622
React-RCTText: 9ccc88273e9a3aacff5094d2175a605efa854dbe
632623
React-RCTVibration: a49a1f42bf8f5acf1c3e297097517c6b3af377ad
633624
ReactCommon: 198c7c8d3591f975e5431bec1b0b3b581aa1c5dd
634625
rn-fetch-blob: f525a73a78df9ed5d35e67ea65e79d53c15255bc
635626
RNCAsyncStorage: 3c304d1adfaea02ec732ac218801cb13897aa8c0
627+
RNCPushNotificationIOS: 4c97a36dbec42dba411cc35e6dac25e34a805fde
636628
RNDeviceInfo: e7c5fcde13d40e161d8a27f6c5dc69c638936002
637629
RNSentry: ae1e005e4f2655775475445a9c49c1d343e8e3a7
638630
RNSound: da030221e6ac7e8290c6b43f2b5f2133a8e225b0
@@ -655,6 +647,6 @@ SPEC CHECKSUMS:
655647
Yoga: f2a7cd4280bfe2cca5a7aed98ba0eb3d1310f18b
656648
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
657649

658-
PODFILE CHECKSUM: b31e45ca912ffe41b915cb3dbc892ca3049708b7
650+
PODFILE CHECKSUM: a8a1bb97c8a90297760ede8d3e44a272c9c337fe
659651

660652
COCOAPODS: 1.9.3

ios/ZulipMobile-Bridging-Header.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,3 @@
66
#import <React/RCTConvert.h>
77
#import <React/RCTEventEmitter.h>
88
#import <React/RCTBundleURLProvider.h>
9-
#import <React/RCTPushNotificationManager.h>

ios/ZulipMobile/AppDelegate.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
#import <React/RCTBridgeDelegate.h>
22
#import <UIKit/UIKit.h>
33
#import <UMReactNativeAdapter/UMModuleRegistryAdapter.h>
4+
#import <UserNotifications/UNUserNotificationCenter.h>
45

5-
@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate>
6+
@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate, UNUserNotificationCenterDelegate>
67

78
@property (nonatomic, strong) UMModuleRegistryAdapter *moduleRegistryAdapter;
89
@property (nonatomic, strong) UIWindow *window;

ios/ZulipMobile/AppDelegate.m

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#import <asl.h>
88
#import <React/RCTLog.h>
99
#import <UserNotifications/UserNotifications.h>
10-
#import <React/RCTPushNotificationManager.h>
10+
#import <RNCPushNotificationIOS.h>
1111
#import <UMCore/UMModuleRegistry.h>
1212
#import <UMReactNativeAdapter/UMNativeModulesProxy.h>
1313
#import <UMReactNativeAdapter/UMModuleRegistryAdapter.h>
@@ -93,34 +93,43 @@ - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserAct
9393
// Required to register for notifications
9494
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
9595
{
96-
[RCTPushNotificationManager didRegisterUserNotificationSettings:notificationSettings];
96+
[RNCPushNotificationIOS didRegisterUserNotificationSettings:notificationSettings];
9797
}
9898

9999
// Required for the register event.
100100
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
101101
{
102-
[RCTPushNotificationManager didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
102+
[RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
103103
}
104104

105105
// Required for the registrationError event.
106106
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
107-
[RCTPushNotificationManager didFailToRegisterForRemoteNotificationsWithError:error];
107+
[RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
108108
}
109109

110110
// Required for the notification event. You must call the completion handler after handling the remote notification.
111111
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
112112
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
113113
{
114-
[RCTPushNotificationManager didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
114+
[RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
115115
}
116116

117-
// Required for the localNotification event.
117+
// iOS 10+ Required for localNotification event
118+
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
119+
didReceiveNotificationResponse:(UNNotificationResponse *)response
120+
withCompletionHandler:(void (^)(void))completionHandler
121+
{
122+
[RNCPushNotificationIOS didReceiveNotificationResponse:response];
123+
completionHandler();
124+
}
125+
126+
// iOS 4-10 Required for the localNotification event.
118127
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
119128
{
120-
[RCTPushNotificationManager didReceiveLocalNotification:notification];
129+
[RNCPushNotificationIOS didReceiveLocalNotification:notification];
121130
}
122131

123-
// Called when a notification is delivered to a foreground app.
132+
// iOS 10.0+: Called when a notification is delivered to a foreground app.
124133
-(void)userNotificationCenter:(UNUserNotificationCenter *)center
125134
willPresentNotification:(UNNotification *)notification
126135
withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler

jest.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const transformModulesWhitelist = [
88
// @rnc/async-storage itself is precompiled, but its mock-helper is not
99
'@react-native-community/async-storage',
1010
'@react-native-community/cameraroll',
11+
'@react-native-community/push-notification-ios',
1112
'@expo/react-native-action-sheet',
1213
'react-navigation',
1314
'@sentry/react-native',

jest/jestSetup.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ jest.mock('react-native', () => {
5555

5656
jest.mock('@react-native-community/async-storage', () => mockAsyncStorage);
5757

58+
// Without this, we get lots of these errors on importing the module:
59+
// `Invariant Violation: Native module cannot be null.`
60+
jest.mock('@react-native-community/push-notification-ios', () => ({
61+
presentLocalNotification: jest.fn(),
62+
scheduleLocalNotification: jest.fn(),
63+
cancelAllLocalNotifications: jest.fn(),
64+
removeAllDeliveredNotifications: jest.fn(),
65+
getDeliveredNotifications: jest.fn(),
66+
removeDeliveredNotifications: jest.fn(),
67+
// etc. (incomplete)
68+
}));
69+
5870
jest.mock('react-native-sound', () => () => ({
5971
play: jest.fn(),
6072
}));

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"@react-native-community/async-storage": "^1.6.3",
3636
"@react-native-community/cameraroll": "^1.7.2",
3737
"@react-native-community/netinfo": "^5.9.5",
38+
"@react-native-community/push-notification-ios": "^1.5.0",
3839
"@sentry/react-native": "^1.0.9",
3940
"@unimodules/core": "~5.1.2",
4041
"@zulip/shared": "^0.0.2",

src/notification/index.js

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* @flow strict-local */
2-
import { DeviceEventEmitter, NativeModules, Platform, PushNotificationIOS } from 'react-native';
3-
import type { PushNotificationEventName } from 'react-native/Libraries/PushNotificationIOS/PushNotificationIOS';
2+
import { DeviceEventEmitter, NativeModules, Platform } from 'react-native';
3+
import PushNotificationIOS from '@react-native-community/push-notification-ios';
4+
import type { PushNotificationEventName } from '@react-native-community/push-notification-ios';
45

56
import type { Notification } from './types';
67
import type { Auth, Dispatch, Identity, Narrow, User } from '../types';
@@ -118,8 +119,8 @@ const getInitialNotification = async (): Promise<Notification | null> => {
118119
}
119120

120121
// This is actually typed as ?Object (and so effectively `any`); but if
121-
// present, it must be a JSONable dictionary. (See PushNotificationIOS.js and
122-
// RCTPushNotificationManager.m in Libraries/PushNotificationIOS.)
122+
// present, it must be a JSONable dictionary. (See js/index.js and
123+
// ios/RNCPushNotificationIOS.m in @rnc-push-notification-ios.)
123124
const data: ?JSONableDict = notification.getData();
124125
if (!data) {
125126
return null;
@@ -263,53 +264,46 @@ export class NotificationListener {
263264
export const getNotificationToken = () => {
264265
if (Platform.OS === 'ios') {
265266
// This leads to a call in RNCPushNotificationIOS to this, to
266-
// maybe prompt the user to grant permissions:
267-
// https://developer.apple.com/documentation/uikit/uiapplication/1622932-registerusernotificationsettings?language=objc
268-
// (deprecated after iOS 10, yikes!).
267+
// maybe prompt the user to grant authorization, with options for
268+
// what things to authorize (badge, sound, alert, etc.):
269+
// https://developer.apple.com/documentation/usernotifications/unusernotificationcenter/1649527-requestauthorizationwithoptions
269270
//
270-
// (Then, in case we're interested, the library ensures that the
271-
// Promise we get will resolve with the user's notification
272-
// settings for the app: whether they've enabled alerts, the badge
273-
// count, and sound.)
271+
// If authorization is granted, the library calls this, to have the
272+
// application register for remote notifications:
273+
// https://developer.apple.com/documentation/appkit/nsapplication/2967172-registerforremotenotifications?language=occ
274274
//
275-
// The above-mentioned `registerUserNotificationSettings` function
276-
// reports the permissions-request result to the app;
277-
// `AppDelegate`'s `didRegisterUserNotificationSettings` method
278-
// gets called (it's also deprecated):
279-
// https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623022-application?language=objc
280-
// Following the library's setup instructions, we've asked that
281-
// method to hand control back to the library.
275+
// (Then, in case we're interested, the library calls
276+
// https://developer.apple.com/documentation/usernotifications/unusernotificationcenter/1649524-getnotificationsettingswithcompl
277+
// and sets the eventual result to be the resolution of the
278+
// Promise we get, so we can know if the user has enabled
279+
// alerts, the badge count, and sound.)
282280
//
283-
// If authorization is granted, the library calls this (not
284-
// deprecated), to have the application register for remote
285-
// notifications:
286-
// https://developer.apple.com/documentation/appkit/nsapplication/2967172-registerforremotenotifications?language=occ
287-
// That function ends up sending the app a device token; the app
288-
// receives it in our own code: `AppDelegate`'s
281+
// The above-mentioned `registerForRemoteNotifications` function
282+
// ends up sending the app a device token; the app receives it in
283+
// our own code: `AppDelegate`'s
289284
// `didRegisterForRemoteNotificationsWithDeviceToken` method:
290-
// https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622958-application?language=objc
291-
// (not deprecated). Following the library's setup instructions,
292-
// we've asked that method to hand control back to the library.
285+
// https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622958-application?language=objc.
286+
// Following the library's setup instructions, we've asked that
287+
// method to hand control back to the library.
293288
//
294289
// It looks like the library then creates a notification, with the
295290
// magic-string name "RemoteNotificationsRegistered", using
296-
// https://developer.apple.com/documentation/foundation/nsnotificationcenter/1415812-postnotificationname?language=objc
297-
// (not deprecated).
291+
// https://developer.apple.com/documentation/foundation/nsnotificationcenter/1415812-postnotificationname?language=objc.
298292
// It listens for this notification with
299293
// https://developer.apple.com/documentation/foundation/nsnotificationcenter/1415360-addobserver
300-
// (not deprecated) and, upon receipt, sends a React Native event
301-
// to the JavaScript part of the library. We can listen to this
302-
// event, with `PushNotificationIOS.addEventListener`, under the
303-
// alias 'register'. (We can also listen for registration failure
304-
// under the alias 'registrationError'.)
294+
// and, upon receipt, sends a React Native event to the JavaScript
295+
// part of the library. We can listen to this event, with
296+
// `PushNotificationIOS.addEventListener`, under the alias
297+
// 'register'. (We can also listen for registration failure under
298+
// the alias 'registrationError'.)
305299
//
306300
// In short, this kicks off a sequence:
307-
// permissions / register settings ->
301+
// authorization, with options ->
308302
// register for remote notifications ->
309303
// send event we already have a global listener for
310304
//
311305
// This satisfies the stern warnings in Apple's docs (at the above
312-
// links) to request permissions before registering with the push
306+
// links) to request authorization before registering with the push
313307
// notification service.
314308
PushNotificationIOS.requestPermissions();
315309
} else {

yarn.lock

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,6 +1503,13 @@
15031503
resolved "https://registry.yarnpkg.com/@react-native-community/netinfo/-/netinfo-5.9.5.tgz#3bad0d855d2e813be085ec305139d4175c512ccc"
15041504
integrity sha512-PbSsRmhRwYIMdeVJTf9gJtvW0TVq/hmgz1xyjsrTIsQ7QS7wbMEiv1Eb/M/y6AEEsdUped5Axm5xykq9TGISHg==
15051505

1506+
"@react-native-community/push-notification-ios@^1.5.0":
1507+
version "1.5.0"
1508+
resolved "https://registry.yarnpkg.com/@react-native-community/push-notification-ios/-/push-notification-ios-1.5.0.tgz#b41802b58d2388c8cb76cd219bbeec9ac9a4c06d"
1509+
integrity sha512-88Uwu6S8oRVnuMfBMGN+MtTyUjiVmMKwfObYrPmm+b2E2Aqk0WlZ4clfECukG8QIzv1pfELJZ5uZMVTYMI6klg==
1510+
dependencies:
1511+
invariant "^2.2.4"
1512+
15061513
"@rollup/plugin-babel@^5.2.0":
15071514
version "5.2.0"
15081515
resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.2.0.tgz#b87556d61ed108b4eaf9d18b5323965adf8d9bee"

0 commit comments

Comments
 (0)