Skip to content

Commit 5bda5b5

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.62 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. We no longer support iOS 10, so we leave out some methods that target iOS <=10. 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.62/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 782c7f6 commit 5bda5b5

File tree

9 files changed

+70
-67
lines changed

9 files changed

+70
-67
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/callinvoker', :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 & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -193,14 +193,6 @@ PODS:
193193
- React-jsi (= 0.62.2)
194194
- React-jsiexecutor (= 0.62.2)
195195
- Yoga
196-
- React-Core/RCTPushNotificationHeaders (0.62.2):
197-
- Folly (= 2018.10.22.00)
198-
- glog
199-
- React-Core/Default
200-
- React-cxxreact (= 0.62.2)
201-
- React-jsi (= 0.62.2)
202-
- React-jsiexecutor (= 0.62.2)
203-
- Yoga
204196
- React-Core/RCTSettingsHeaders (0.62.2):
205197
- Folly (= 2018.10.22.00)
206198
- glog
@@ -316,11 +308,6 @@ PODS:
316308
- RCTTypeSafety (= 0.62.2)
317309
- React-Core/RCTNetworkHeaders (= 0.62.2)
318310
- ReactCommon/turbomodule/core (= 0.62.2)
319-
- React-RCTPushNotification (0.62.2):
320-
- FBReactNativeSpec (= 0.62.2)
321-
- RCTTypeSafety (= 0.62.2)
322-
- React-Core/RCTPushNotificationHeaders (= 0.62.2)
323-
- ReactCommon/turbomodule/core (= 0.62.2)
324311
- React-RCTSettings (0.62.2):
325312
- FBReactNativeSpec (= 0.62.2)
326313
- Folly (= 2018.10.22.00)
@@ -353,6 +340,8 @@ PODS:
353340
- React
354341
- RNCMaskedView (0.1.10):
355342
- React
343+
- RNCPushNotificationIOS (1.7.3):
344+
- React-Core
356345
- RNDeviceInfo (6.0.2):
357346
- React
358347
- RNGestureHandler (1.8.0):
@@ -453,7 +442,6 @@ DEPENDENCIES:
453442
- React-RCTImage (from `../node_modules/react-native/Libraries/Image`)
454443
- React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`)
455444
- React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`)
456-
- React-RCTPushNotification (from `../node_modules/react-native/Libraries/PushNotificationIOS`)
457445
- React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
458446
- React-RCTText (from `../node_modules/react-native/Libraries/Text`)
459447
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
@@ -462,6 +450,7 @@ DEPENDENCIES:
462450
- rn-fetch-blob (from `../node_modules/rn-fetch-blob`)
463451
- "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)"
464452
- "RNCMaskedView (from `../node_modules/@react-native-community/masked-view`)"
453+
- "RNCPushNotificationIOS (from `../node_modules/@react-native-community/push-notification-ios`)"
465454
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
466455
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
467456
- RNReanimated (from `../node_modules/react-native-reanimated`)
@@ -575,8 +564,6 @@ EXTERNAL SOURCES:
575564
:path: "../node_modules/react-native/Libraries/LinkingIOS"
576565
React-RCTNetwork:
577566
:path: "../node_modules/react-native/Libraries/Network"
578-
React-RCTPushNotification:
579-
:path: "../node_modules/react-native/Libraries/PushNotificationIOS"
580567
React-RCTSettings:
581568
:path: "../node_modules/react-native/Libraries/Settings"
582569
React-RCTText:
@@ -591,6 +578,8 @@ EXTERNAL SOURCES:
591578
:path: "../node_modules/@react-native-community/async-storage"
592579
RNCMaskedView:
593580
:path: "../node_modules/@react-native-community/masked-view"
581+
RNCPushNotificationIOS:
582+
:path: "../node_modules/@react-native-community/push-notification-ios"
594583
RNDeviceInfo:
595584
:path: "../node_modules/react-native-device-info"
596585
RNGestureHandler:
@@ -681,14 +670,14 @@ SPEC CHECKSUMS:
681670
React-RCTImage: e70be9b9c74fe4e42d0005f42cace7981c994ac3
682671
React-RCTLinking: c1b9739a88d56ecbec23b7f63650e44672ab2ad2
683672
React-RCTNetwork: 73138b6f45e5a2768ad93f3d57873c2a18d14b44
684-
React-RCTPushNotification: d544b6b5bf8def493b87da896a1cc0f4b61291c7
685673
React-RCTSettings: 6e3738a87e21b39a8cb08d627e68c44acf1e325a
686674
React-RCTText: fae545b10cfdb3d247c36c56f61a94cfd6dba41d
687675
React-RCTVibration: 4356114dbcba4ce66991096e51a66e61eda51256
688676
ReactCommon: ed4e11d27609d571e7eee8b65548efc191116eb3
689677
rn-fetch-blob: f525a73a78df9ed5d35e67ea65e79d53c15255bc
690678
RNCAsyncStorage: 3c304d1adfaea02ec732ac218801cb13897aa8c0
691679
RNCMaskedView: 5a8ec07677aa885546a0d98da336457e2bea557f
680+
RNCPushNotificationIOS: edeeea93b7210d2f918fc0e46e1a2a189b5fdacc
692681
RNDeviceInfo: bdd61e8b070d13a1dd9d022091981075ed4cde16
693682
RNGestureHandler: 7a5833d0f788dbd107fbb913e09aa0c1ff333c39
694683
RNReanimated: 89f5e0a04d1dd52fbf27e7e7030d8f80a646a3fc
@@ -713,6 +702,6 @@ SPEC CHECKSUMS:
713702
Yoga: 3ebccbdd559724312790e7742142d062476b698e
714703
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
715704

716-
PODFILE CHECKSUM: 225a865018bba07be314e8afa4e91319ab40adac
705+
PODFILE CHECKSUM: bb21f5f2cffae3c57e18eab3696b63eff8e52585
717706

718707
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.m

Lines changed: 11 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>
@@ -99,31 +99,34 @@ - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserAct
9999
// Required to register for notifications
100100
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
101101
{
102-
[RCTPushNotificationManager didRegisterUserNotificationSettings:notificationSettings];
102+
[RNCPushNotificationIOS didRegisterUserNotificationSettings:notificationSettings];
103103
}
104104

105105
// Required for the register event.
106106
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
107107
{
108-
[RCTPushNotificationManager didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
108+
[RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
109109
}
110110

111111
// Required for the registrationError event.
112112
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
113-
[RCTPushNotificationManager didFailToRegisterForRemoteNotificationsWithError:error];
113+
[RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
114114
}
115115

116116
// Required for the notification event. You must call the completion handler after handling the remote notification.
117117
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
118118
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
119119
{
120-
[RCTPushNotificationManager didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
120+
[RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
121121
}
122122

123-
// Required for the localNotification event.
124-
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
123+
// Required for localNotification event
124+
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
125+
didReceiveNotificationResponse:(UNNotificationResponse *)response
126+
withCompletionHandler:(void (^)(void))completionHandler
125127
{
126-
[RCTPushNotificationManager didReceiveLocalNotification:notification];
128+
[RNCPushNotificationIOS didReceiveNotificationResponse:response];
129+
completionHandler();
127130
}
128131

129132
// Called when a notification is delivered to a foreground app.

jest.config.js

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

jest/jestSetup.js

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

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

70+
// Without this, we get lots of these errors on importing the module:
71+
// `Invariant Violation: Native module cannot be null.`
72+
jest.mock('@react-native-community/push-notification-ios', () => ({
73+
presentLocalNotification: jest.fn(),
74+
scheduleLocalNotification: jest.fn(),
75+
cancelAllLocalNotifications: jest.fn(),
76+
removeAllDeliveredNotifications: jest.fn(),
77+
getDeliveredNotifications: jest.fn(),
78+
removeDeliveredNotifications: jest.fn(),
79+
// etc. (incomplete)
80+
}));
81+
7082
jest.mock('react-native-sound', () => () => ({
7183
play: jest.fn(),
7284
}));

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"@react-native-community/cameraroll": "^1.7.2",
3737
"@react-native-community/masked-view": "^0.1.10",
3838
"@react-native-community/netinfo": "^5.9.5",
39+
"@react-native-community/push-notification-ios": "^1.5.0",
3940
"@sentry/react-native": "^1.0.9",
4041
"@unimodules/core": "~5.3.0",
4142
"@zulip/shared": "^0.0.2",

src/notification/index.js

Lines changed: 31 additions & 37 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';
@@ -122,8 +123,8 @@ const getInitialNotification = async (): Promise<Notification | null> => {
122123
}
123124

124125
// This is actually typed as ?Object (and so effectively `any`); but if
125-
// present, it must be a JSONable dictionary. (See PushNotificationIOS.js and
126-
// RCTPushNotificationManager.m in Libraries/PushNotificationIOS.)
126+
// present, it must be a JSONable dictionary. (See js/index.js and
127+
// ios/RNCPushNotificationIOS.m in @rnc/push-notification-ios.)
127128
const data: ?JSONableDict = notification.getData();
128129
if (!data) {
129130
return null;
@@ -177,7 +178,7 @@ export class NotificationListener {
177178
// 'register' -> 'remoteNotificationsRegistered'
178179
// 'registrationError' -> 'remoteNotificationRegistrationError'
179180
PushNotificationIOS.addEventListener(name, handler);
180-
this.unsubs.push(() => PushNotificationIOS.removeEventListener(name, handler));
181+
this.unsubs.push(() => PushNotificationIOS.removeEventListener(name));
181182
}
182183

183184
/** Private. */
@@ -272,53 +273,46 @@ export class NotificationListener {
272273
export const getNotificationToken = () => {
273274
if (Platform.OS === 'ios') {
274275
// This leads to a call in RNCPushNotificationIOS to this, to
275-
// maybe prompt the user to grant permissions:
276-
// https://developer.apple.com/documentation/uikit/uiapplication/1622932-registerusernotificationsettings?language=objc
277-
// (deprecated after iOS 10, yikes!).
276+
// maybe prompt the user to grant authorization, with options for
277+
// what things to authorize (badge, sound, alert, etc.):
278+
// https://developer.apple.com/documentation/usernotifications/unusernotificationcenter/1649527-requestauthorizationwithoptions
278279
//
279-
// (Then, in case we're interested, the library ensures that the
280-
// Promise we get will resolve with the user's notification
281-
// settings for the app: whether they've enabled alerts, the badge
282-
// count, and sound.)
280+
// If authorization is granted, the library calls this, to have the
281+
// application register for remote notifications:
282+
// https://developer.apple.com/documentation/appkit/nsapplication/2967172-registerforremotenotifications?language=occ
283283
//
284-
// The above-mentioned `registerUserNotificationSettings` function
285-
// reports the permissions-request result to the app;
286-
// `AppDelegate`'s `didRegisterUserNotificationSettings` method
287-
// gets called (it's also deprecated):
288-
// https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623022-application?language=objc
289-
// Following the library's setup instructions, we've asked that
290-
// method to hand control back to the library.
284+
// (Then, in case we're interested, the library calls
285+
// https://developer.apple.com/documentation/usernotifications/unusernotificationcenter/1649524-getnotificationsettingswithcompl
286+
// and sets the eventual result to be the resolution of the
287+
// Promise we get, so we can know if the user has enabled
288+
// alerts, the badge count, and sound.)
291289
//
292-
// If authorization is granted, the library calls this (not
293-
// deprecated), to have the application register for remote
294-
// notifications:
295-
// https://developer.apple.com/documentation/appkit/nsapplication/2967172-registerforremotenotifications?language=occ
296-
// That function ends up sending the app a device token; the app
297-
// receives it in our own code: `AppDelegate`'s
290+
// The above-mentioned `registerForRemoteNotifications` function
291+
// ends up sending the app a device token; the app receives it in
292+
// our own code: `AppDelegate`'s
298293
// `didRegisterForRemoteNotificationsWithDeviceToken` method:
299-
// https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622958-application?language=objc
300-
// (not deprecated). Following the library's setup instructions,
301-
// we've asked that method to hand control back to the library.
294+
// https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622958-application?language=objc.
295+
// Following the library's setup instructions, we've asked that
296+
// method to hand control back to the library.
302297
//
303298
// It looks like the library then creates a notification, with the
304299
// magic-string name "RemoteNotificationsRegistered", using
305-
// https://developer.apple.com/documentation/foundation/nsnotificationcenter/1415812-postnotificationname?language=objc
306-
// (not deprecated).
300+
// https://developer.apple.com/documentation/foundation/nsnotificationcenter/1415812-postnotificationname?language=objc.
307301
// It listens for this notification with
308302
// https://developer.apple.com/documentation/foundation/nsnotificationcenter/1415360-addobserver
309-
// (not deprecated) and, upon receipt, sends a React Native event
310-
// to the JavaScript part of the library. We can listen to this
311-
// event, with `PushNotificationIOS.addEventListener`, under the
312-
// alias 'register'. (We can also listen for registration failure
313-
// under the alias 'registrationError'.)
303+
// and, upon receipt, sends a React Native event to the JavaScript
304+
// part of the library. We can listen to this event, with
305+
// `PushNotificationIOS.addEventListener`, under the alias
306+
// 'register'. (We can also listen for registration failure under
307+
// the alias 'registrationError'.)
314308
//
315309
// In short, this kicks off a sequence:
316-
// permissions / register settings ->
310+
// authorization, with options ->
317311
// register for remote notifications ->
318312
// send event we already have a global listener for
319313
//
320314
// This satisfies the stern warnings in Apple's docs (at the above
321-
// links) to request permissions before registering with the push
315+
// links) to request authorization before registering with the push
322316
// notification service.
323317
PushNotificationIOS.requestPermissions();
324318
} else {

yarn.lock

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

2203+
"@react-native-community/push-notification-ios@^1.5.0":
2204+
version "1.7.3"
2205+
resolved "https://registry.yarnpkg.com/@react-native-community/push-notification-ios/-/push-notification-ios-1.7.3.tgz#7b41add329996df59382820d8a729fe609c2fb75"
2206+
integrity sha512-SLGQMxSB4WTvATjCXELxansnseLcmqJ6jIC8U4AyjxL30k3m1YmbrO4wGMw/ZF/VSC1toK+a39aD+ozDjon3mw==
2207+
dependencies:
2208+
invariant "^2.2.4"
2209+
22032210
"@react-navigation/core@^3.7.6":
22042211
version "3.7.6"
22052212
resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-3.7.6.tgz#e0244fcdc22937825b252197f70308bbe5709c58"

0 commit comments

Comments
 (0)