Open saqlain455 opened 3 years ago
this package is not compatible with expo, try expo-notifications
Clean your node modules and remove react-native-push-notification/ios
package. You can eject your expo project to bare workflow using expo eject
command. After that install package and follow guide.
You can actually have an expo managed build by doing the following
{
...
"ios": {
"infoPlist": {
...
"UIBackgroundModes": ["remote-notification", ...]
}
}
This is a helpful article on how to create a custom plugin
Soooo... Based on the instructions above, I got this. Provided without any guarantees. Enjoy.
import fs from 'node:fs';
import { withAppDelegate, withMod, BaseMods, IOSConfig } from 'expo/config-plugins';
import { toMerged } from 'es-toolkit';
import type { ExpoConfig } from 'expo/config';
import type { ConfigPlugin, ExportedConfig, Mod } from 'expo/config-plugins';
/**
* A plugin which adds new base modifiers to the prebuild config.
*/
function withAppDelegateHeaderBaseMod(config: ExportedConfig) {
return BaseMods.withGeneratedBaseMods<'appDelegateHeader'>(config, {
platform: 'ios',
providers: {
// Append a custom rule to supply AppDelegate header data to mods on `mods.ios.appDelegateHeader`
appDelegateHeader: BaseMods.provider<IOSConfig.Paths.AppDelegateProjectFile>({
// Get the local filepath that should be passed to the `read` method.
getFilePath({ modRequest: { projectRoot } }) {
const filePath = IOSConfig.Paths.getAppDelegateFilePath(projectRoot);
// Replace the .m/.mm with a .h
if (filePath.endsWith('.m') || filePath.endsWith('.mm')) {
return `${filePath.slice(0, filePath.lastIndexOf('.'))}.h`;
}
throw new Error(`Could not locate a valid AppDelegate.h at root: "${projectRoot}"`);
},
// Read the input file from the filesystem.
async read(filePath) {
return IOSConfig.Paths.getFileInfo(filePath);
},
// Write the resulting output to the filesystem.
async write(filePath: string, { modResults: { contents } }) {
await fs.promises.writeFile(filePath, contents);
},
}),
},
});
}
const withAppDelegateHeader: ConfigPlugin<Mod<IOSConfig.Paths.AppDelegateProjectFile>> = (
config,
action,
) => {
return withMod(config, {
platform: 'ios',
mod: 'appDelegateHeader',
action,
});
};
const withPushNotificationsIOS: ConfigPlugin = (config) => {
const configWithAppDelegateHeader = withAppDelegateHeader(config, (appDelegateHeader) => {
appDelegateHeader.modResults.contents = appDelegateHeader.modResults.contents
.split('\n')
.toSpliced(
appDelegateHeader.modResults.contents.split('\n').indexOf('#import <Expo/Expo.h>') + 1,
0,
'#import <UserNotifications/UNUserNotificationCenter.h>',
)
.join('\n');
appDelegateHeader.modResults.contents = appDelegateHeader.modResults.contents
.split('\n')
.toSpliced(
appDelegateHeader.modResults.contents
.split('\n')
.indexOf('@interface AppDelegate : EXAppDelegateWrapper'),
1,
'@interface AppDelegate : EXAppDelegateWrapper <UNUserNotificationCenterDelegate>',
)
.join('\n');
return appDelegateHeader;
});
const configWithAppDelegate = withAppDelegate(configWithAppDelegateHeader, (appDelegate) => {
appDelegate.modResults.contents = appDelegate.modResults.contents
.split('\n')
.toSpliced(
1,
0,
`#import <UserNotifications/UserNotifications.h>
#import <RNCPushNotificationIOS.h>`,
)
.join('\n');
appDelegate.modResults.contents = appDelegate.modResults.contents
.split('\n')
.toSpliced(
appDelegate.modResults.contents
.split('\n')
.indexOf(
' return [super application:application didFinishLaunchingWithOptions:launchOptions];',
),
0,
` // Define UNUserNotificationCenter
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
`,
)
.join('\n');
appDelegate.modResults.contents = appDelegate.modResults.contents
.split('\n')
.toSpliced(
appDelegate.modResults.contents
.split('\n')
.indexOf(
' return [super application:application didFinishLaunchingWithOptions:launchOptions];',
) + 2,
0,
`
// Called when a notification is delivered to a foreground app.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);
}`,
)
.join('\n');
appDelegate.modResults.contents = appDelegate.modResults.contents
.replace(
'return [super application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];',
'[RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];',
)
.replace(
'return [super application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];',
'[RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];',
)
.replace(
'return [super application:application didFailToRegisterForRemoteNotificationsWithError:error];',
'[RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];',
);
appDelegate.modResults.contents = appDelegate.modResults.contents
.split('\n')
.toSpliced(
appDelegate.modResults.contents.split('\n').indexOf('@end'),
0,
`// Required for localNotification event
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler
{
[RNCPushNotificationIOS didReceiveNotificationResponse:response];
}
`,
)
.join('\n');
return appDelegate;
});
return toMerged(configWithAppDelegate, {
ios: {
entitlements: {
'aps-environment': process.env.NODE_ENV === 'production' ? 'production' : 'development',
},
},
plugins: [withAppDelegateHeaderBaseMod],
}) satisfies ExpoConfig;
};
Invariant Violation: Native module cannot be null. how I can solve this issue