onesignal-expo-plugin 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/build/onesignal/withOneSignal.d.ts +8 -0
- package/build/onesignal/withOneSignalAndroid.d.ts +7 -0
- package/build/onesignal/withOneSignalAndroid.js +48 -20
- package/build/onesignal/withOneSignalIos.d.ts +13 -0
- package/build/onesignal/withOneSignalIos.js +67 -14
- package/build/support/FileManager.d.ts +9 -0
- package/build/support/NseUpdaterManager.d.ts +8 -0
- package/build/support/OneSignalLog.d.ts +4 -0
- package/build/support/eas/getEasManagedCredentialsConfigExtra.d.ts +4 -0
- package/build/support/helpers.d.ts +7 -0
- package/build/support/helpers.js +46 -3
- package/build/support/iosConstants.d.ts +12 -0
- package/build/support/serviceExtensionFiles/NotificationService.m +17 -12
- package/build/support/updatePodfile.d.ts +1 -0
- package/build/types/types.d.ts +62 -0
- package/build/types/types.js +3 -6
- package/package.json +11 -5
package/README.md
CHANGED
|
@@ -81,7 +81,7 @@ You can pass props to the plugin config object to configure:
|
|
|
81
81
|
| Plugin Prop | | |
|
|
82
82
|
| ------------------------ | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
83
83
|
| `mode` | **required** | Used to configure [APNs environment](https://developer.apple.com/documentation/bundleresources/entitlements/aps-environment) entitlement. `"development"` or `"production"` |
|
|
84
|
-
| `devTeam` |
|
|
84
|
+
| `devTeam` | **deprecated** | Use [`ios.appleTeamId`](https://docs.expo.dev/versions/latest/config/app/#appleteamid) in your Expo config instead. Falls back to this value if `appleTeamId` is not set. e.g: `"91SW8A37CR"` |
|
|
85
85
|
| `iPhoneDeploymentTarget` | optional | Target `IPHONEOS_DEPLOYMENT_TARGET` value to be used when adding the iOS [NSE](https://documentation.onesignal.com/docs/service-extensions). A deployment target is nothing more than the minimum version of the operating system the application can run on. This value should match the value in your Podfile e.g: `"12.0"`. |
|
|
86
86
|
| `smallIcons` | optional | An array of local paths to small notification icons for Android. Image should be white, transparent, and 96x96 in size. Input images will be automatically scaled down and placed in the appropriate resource folders. e.g: `["./assets/ic_stat_onesignal_default.png"]`. See https://documentation.onesignal.com/docs/customize-notification-icons#small-notification-icons. |
|
|
87
87
|
| `largeIcons` | optional | An array of local paths to large notification icons for Android. Image should be white, transparent, and 256x256 in size. e.g: `["./assets/ic_onesignal_large_icon_default.png"]`. See https://documentation.onesignal.com/docs/customize-notification-icons#large-notification-icons. |
|
|
@@ -89,6 +89,8 @@ You can pass props to the plugin config object to configure:
|
|
|
89
89
|
| `iosNSEFilePath` | optional | The local path to a custom Notification Service Extension (NSE), written in Objective-C. The NSE will typically start as a copy of the [default NSE](https://github.com/OneSignal/onesignal-expo-plugin/blob/main/support/serviceExtensionFiles/NotificationService.m), then altered to support any custom logic required. e.g: `"./assets/NotificationService.m"`. |
|
|
90
90
|
| `appGroupName` | optional | Used to configure a custom iOS [App Group](https://documentation.onesignal.com/docs/ios-sdk-setup#step-3-create-an-app-group) name. If not provided, defaults to `"group.{ios.bundleIdentifier}.onesignal"`. e.g: `"group.com.example.myapp.onesignal2"`. |
|
|
91
91
|
| `nseBundleIdentifier` | optional | Used to configure a custom bundle identifier suffix for the iOS Notification Service Extension. The full bundle identifier will be `"{ios.bundleIdentifier}.{nseBundleIdentifier}"`. If not provided, defaults to `"OneSignalNotificationServiceExtension"`. |
|
|
92
|
+
| `disableNSE` | optional | If `true`, the iOS Notification Service Extension (NSE) will not be added to the project. The NSE is required for badges, confirmed delivery, media attachments, and action buttons. Only disable this if you only need basic push notifications. |
|
|
93
|
+
| `sounds` | optional | An array of local paths to custom notification sound files (`.wav` only, ≤30 seconds). Files are copied into the app bundle on iOS and `res/raw/` on Android. e.g: `["./assets/notification_sound.wav"]`. See https://documentation.onesignal.com/docs/customize-notification-sounds. |
|
|
92
94
|
|
|
93
95
|
### OneSignal App ID
|
|
94
96
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expo config plugin for One Signal
|
|
3
|
+
* @see https://documentation.onesignal.com/docs/react-native-sdk-setup#step-4-install-for-ios-using-cocoapods-for-ios-apps
|
|
4
|
+
*/
|
|
5
|
+
import { ConfigPlugin } from '@expo/config-plugins';
|
|
6
|
+
import { OneSignalPluginProps } from '../types/types';
|
|
7
|
+
declare const withOneSignal: ConfigPlugin<OneSignalPluginProps>;
|
|
8
|
+
export default withOneSignal;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expo config plugin for OneSignal (Android)
|
|
3
|
+
* @see https://documentation.onesignal.com/docs/react-native-sdk-setup#step-4-install-for-ios-using-cocoapods-for-ios-apps
|
|
4
|
+
*/
|
|
5
|
+
import { ConfigPlugin } from '@expo/config-plugins';
|
|
6
|
+
import { OneSignalPluginProps } from '../types/types';
|
|
7
|
+
export declare const withOneSignalAndroid: ConfigPlugin<OneSignalPluginProps>;
|
|
@@ -8,6 +8,7 @@ exports.withOneSignalAndroid = void 0;
|
|
|
8
8
|
const config_plugins_1 = require("@expo/config-plugins");
|
|
9
9
|
const image_utils_1 = require("@expo/image-utils");
|
|
10
10
|
const OneSignalLog_1 = require("../support/OneSignalLog");
|
|
11
|
+
const helpers_1 = require("../support/helpers");
|
|
11
12
|
const path_1 = require("path");
|
|
12
13
|
const fs_1 = require("fs");
|
|
13
14
|
const RESOURCE_ROOT_PATH = 'android/app/src/main/res/';
|
|
@@ -23,34 +24,34 @@ const SMALL_ICON_DIRS_TO_SIZE = {
|
|
|
23
24
|
const LARGE_ICON_DIRS_TO_SIZE = {
|
|
24
25
|
'drawable-xxxhdpi': 256,
|
|
25
26
|
};
|
|
27
|
+
const SMALL_ICON_DEFAULT_NAME = 'ic_stat_onesignal_default';
|
|
26
28
|
const withSmallIcons = (config, onesignalProps) => {
|
|
27
29
|
if (!onesignalProps.smallIcons && !config.notification?.icon) {
|
|
28
30
|
return config;
|
|
29
31
|
}
|
|
30
|
-
// we are modifying the android build (adding files) without a base mod
|
|
31
32
|
return (0, config_plugins_1.withDangerousMod)(config, [
|
|
32
33
|
'android',
|
|
33
34
|
async (config) => {
|
|
34
35
|
if (config.notification?.icon) {
|
|
35
|
-
await saveIconAsync(config.notification.icon, config.modRequest.projectRoot, SMALL_ICON_DIRS_TO_SIZE);
|
|
36
|
+
await saveIconAsync(config.notification.icon, config.modRequest.projectRoot, SMALL_ICON_DIRS_TO_SIZE, SMALL_ICON_DEFAULT_NAME);
|
|
36
37
|
}
|
|
37
38
|
if (onesignalProps.smallIcons) {
|
|
38
|
-
await saveIconsArrayAsync(config.modRequest.projectRoot, onesignalProps.smallIcons, SMALL_ICON_DIRS_TO_SIZE);
|
|
39
|
+
await saveIconsArrayAsync(config.modRequest.projectRoot, onesignalProps.smallIcons, SMALL_ICON_DIRS_TO_SIZE, SMALL_ICON_DEFAULT_NAME);
|
|
39
40
|
}
|
|
40
41
|
return config;
|
|
41
42
|
},
|
|
42
43
|
]);
|
|
43
44
|
};
|
|
45
|
+
const LARGE_ICON_DEFAULT_NAME = 'ic_onesignal_large_icon_default';
|
|
44
46
|
const withLargeIcons = (config, onesignalProps) => {
|
|
45
47
|
if (!onesignalProps.largeIcons) {
|
|
46
48
|
return config;
|
|
47
49
|
}
|
|
48
|
-
// we are modifying the android build (adding files) without a base mod
|
|
49
50
|
return (0, config_plugins_1.withDangerousMod)(config, [
|
|
50
51
|
'android',
|
|
51
52
|
async (config) => {
|
|
52
53
|
if (onesignalProps.largeIcons) {
|
|
53
|
-
await saveIconsArrayAsync(config.modRequest.projectRoot, onesignalProps.largeIcons, LARGE_ICON_DIRS_TO_SIZE);
|
|
54
|
+
await saveIconsArrayAsync(config.modRequest.projectRoot, onesignalProps.largeIcons, LARGE_ICON_DIRS_TO_SIZE, LARGE_ICON_DEFAULT_NAME);
|
|
54
55
|
}
|
|
55
56
|
return config;
|
|
56
57
|
},
|
|
@@ -61,28 +62,32 @@ const withSmallIconAccentColor = (config, onesignalProps) => {
|
|
|
61
62
|
return config;
|
|
62
63
|
}
|
|
63
64
|
return (0, config_plugins_1.withStringsXml)(config, (config) => {
|
|
64
|
-
const colorInARGB =
|
|
65
|
+
const colorInARGB = (0, helpers_1.parseColorToARGB)(onesignalProps.smallIconAccentColor ?? '');
|
|
65
66
|
const strings = config.modResults.resources.string ?? [];
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
};
|
|
74
|
-
config.modResults.resources.string = [...strings, accentColorEntry];
|
|
67
|
+
const existingIndex = strings.findIndex((stringEntry) => stringEntry.$?.name === 'onesignal_notification_accent_color');
|
|
68
|
+
const accentColorEntry = {
|
|
69
|
+
$: { name: 'onesignal_notification_accent_color' },
|
|
70
|
+
_: colorInARGB,
|
|
71
|
+
};
|
|
72
|
+
if (existingIndex !== -1) {
|
|
73
|
+
strings[existingIndex] = accentColorEntry;
|
|
75
74
|
}
|
|
75
|
+
else {
|
|
76
|
+
strings.push(accentColorEntry);
|
|
77
|
+
}
|
|
78
|
+
config.modResults.resources.string = strings;
|
|
76
79
|
return config;
|
|
77
80
|
});
|
|
78
81
|
};
|
|
79
|
-
async function saveIconsArrayAsync(projectRoot, icons, dirsToSize) {
|
|
80
|
-
for (
|
|
81
|
-
|
|
82
|
+
async function saveIconsArrayAsync(projectRoot, icons, dirsToSize, defaultName) {
|
|
83
|
+
for (let i = 0; i < icons.length; i++) {
|
|
84
|
+
// the first icon should use OneSignal’s required default drawable name; others keep their file-derived names.
|
|
85
|
+
const outputName = i === 0 ? defaultName : undefined;
|
|
86
|
+
await saveIconAsync(icons[i], projectRoot, dirsToSize, outputName);
|
|
82
87
|
}
|
|
83
88
|
}
|
|
84
|
-
async function saveIconAsync(icon, projectRoot, dirsToSize) {
|
|
85
|
-
const name = (0, path_1.parse)(icon).name;
|
|
89
|
+
async function saveIconAsync(icon, projectRoot, dirsToSize, outputName) {
|
|
90
|
+
const name = outputName ?? (0, path_1.parse)(icon).name;
|
|
86
91
|
OneSignalLog_1.OneSignalLog.log('Saving icon ' + icon + ' as drawable resource ' + name);
|
|
87
92
|
for (const iconResourceDir in dirsToSize) {
|
|
88
93
|
const path = (0, path_1.resolve)(projectRoot, RESOURCE_ROOT_PATH, iconResourceDir);
|
|
@@ -99,10 +104,33 @@ async function saveIconAsync(icon, projectRoot, dirsToSize) {
|
|
|
99
104
|
(0, fs_1.writeFileSync)((0, path_1.resolve)(path, name + '.png'), resizedIcon);
|
|
100
105
|
}
|
|
101
106
|
}
|
|
107
|
+
const withSoundFiles = (config, onesignalProps) => {
|
|
108
|
+
if (!onesignalProps.sounds) {
|
|
109
|
+
return config;
|
|
110
|
+
}
|
|
111
|
+
return (0, config_plugins_1.withDangerousMod)(config, [
|
|
112
|
+
'android',
|
|
113
|
+
async (config) => {
|
|
114
|
+
const projectRoot = config.modRequest.projectRoot;
|
|
115
|
+
const rawDir = (0, path_1.resolve)(projectRoot, RESOURCE_ROOT_PATH, 'raw');
|
|
116
|
+
if (!(0, fs_1.existsSync)(rawDir)) {
|
|
117
|
+
(0, fs_1.mkdirSync)(rawDir, { recursive: true });
|
|
118
|
+
}
|
|
119
|
+
for (const soundFile of onesignalProps.sounds) {
|
|
120
|
+
const sourcePath = (0, path_1.resolve)(projectRoot, soundFile);
|
|
121
|
+
const fileName = (0, path_1.basename)(sourcePath).toLowerCase();
|
|
122
|
+
OneSignalLog_1.OneSignalLog.log(`Copying sound file ${soundFile} to res/raw/${fileName}`);
|
|
123
|
+
(0, fs_1.copyFileSync)(sourcePath, (0, path_1.resolve)(rawDir, fileName));
|
|
124
|
+
}
|
|
125
|
+
return config;
|
|
126
|
+
},
|
|
127
|
+
]);
|
|
128
|
+
};
|
|
102
129
|
const withOneSignalAndroid = (config, props) => {
|
|
103
130
|
config = withSmallIcons(config, props);
|
|
104
131
|
config = withLargeIcons(config, props);
|
|
105
132
|
config = withSmallIconAccentColor(config, props);
|
|
133
|
+
config = withSoundFiles(config, props);
|
|
106
134
|
return config;
|
|
107
135
|
};
|
|
108
136
|
exports.withOneSignalAndroid = withOneSignalAndroid;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expo config plugin for One Signal (iOS)
|
|
3
|
+
* @see https://documentation.onesignal.com/docs/react-native-sdk-setup#step-4-install-for-ios-using-cocoapods-for-ios-apps
|
|
4
|
+
*/
|
|
5
|
+
import { ConfigPlugin } from '@expo/config-plugins';
|
|
6
|
+
import { OneSignalPluginProps } from '../types/types';
|
|
7
|
+
import { ExpoConfig } from '@expo/config-types';
|
|
8
|
+
/**
|
|
9
|
+
* Resolve the Apple development team ID. Prefers `ios.appleTeamId` from the
|
|
10
|
+
* Expo config, falling back to the plugin's deprecated `devTeam` prop.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveDevTeam(config: ExpoConfig, props: OneSignalPluginProps): string | undefined;
|
|
13
|
+
export declare const withOneSignalIos: ConfigPlugin<OneSignalPluginProps>;
|
|
@@ -41,6 +41,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
41
41
|
};
|
|
42
42
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
43
|
exports.withOneSignalIos = void 0;
|
|
44
|
+
exports.resolveDevTeam = resolveDevTeam;
|
|
44
45
|
const config_plugins_1 = require("@expo/config-plugins");
|
|
45
46
|
const fs = __importStar(require("fs"));
|
|
46
47
|
const path = __importStar(require("path"));
|
|
@@ -50,7 +51,6 @@ const updatePodfile_1 = require("../support/updatePodfile");
|
|
|
50
51
|
const NseUpdaterManager_1 = __importDefault(require("../support/NseUpdaterManager"));
|
|
51
52
|
const OneSignalLog_1 = require("../support/OneSignalLog");
|
|
52
53
|
const FileManager_1 = require("../support/FileManager");
|
|
53
|
-
const assert_1 = __importDefault(require("assert"));
|
|
54
54
|
const getEasManagedCredentialsConfigExtra_1 = __importDefault(require("../support/eas/getEasManagedCredentialsConfigExtra"));
|
|
55
55
|
/**
|
|
56
56
|
* Add 'aps-environment' record with current environment to '<project-name>.entitlements' file
|
|
@@ -118,7 +118,9 @@ const withCustomAppGroupsKey = (config, props) => {
|
|
|
118
118
|
});
|
|
119
119
|
};
|
|
120
120
|
const withEasManagedCredentials = (config, props) => {
|
|
121
|
-
|
|
121
|
+
if (!config.ios?.bundleIdentifier) {
|
|
122
|
+
return config;
|
|
123
|
+
}
|
|
122
124
|
config.extra = (0, getEasManagedCredentialsConfigExtra_1.default)(config, props?.appGroupName, props?.nseBundleIdentifier);
|
|
123
125
|
return config;
|
|
124
126
|
};
|
|
@@ -133,12 +135,12 @@ const withOneSignalPodfile = (config) => {
|
|
|
133
135
|
]);
|
|
134
136
|
};
|
|
135
137
|
const withOneSignalNSE = (config, props) => {
|
|
136
|
-
// support for monorepos where node_modules can be above the project directory.
|
|
137
|
-
const pluginDir = require.resolve('onesignal-expo-plugin/package.json');
|
|
138
|
-
const sourceDir = path.join(pluginDir, '../build/support/serviceExtensionFiles/');
|
|
139
138
|
return (0, config_plugins_1.withDangerousMod)(config, [
|
|
140
139
|
'ios',
|
|
141
140
|
async (config) => {
|
|
141
|
+
// support for monorepos where node_modules can be above the project directory.
|
|
142
|
+
const pluginDir = require.resolve('onesignal-expo-plugin/package.json');
|
|
143
|
+
const sourceDir = path.join(pluginDir, '../build/support/serviceExtensionFiles/');
|
|
142
144
|
const iosPath = path.join(config.modRequest.projectRoot, 'ios');
|
|
143
145
|
/* COPY OVER EXTENSION FILES */
|
|
144
146
|
fs.mkdirSync(`${iosPath}/${iosConstants_1.NSE_TARGET_NAME}`, {
|
|
@@ -164,10 +166,30 @@ const withOneSignalNSE = (config, props) => {
|
|
|
164
166
|
},
|
|
165
167
|
]);
|
|
166
168
|
};
|
|
169
|
+
/**
|
|
170
|
+
* Resolve the Apple development team ID. Prefers `ios.appleTeamId` from the
|
|
171
|
+
* Expo config, falling back to the plugin's deprecated `devTeam` prop.
|
|
172
|
+
*/
|
|
173
|
+
function resolveDevTeam(config, props) {
|
|
174
|
+
if (config.ios?.appleTeamId) {
|
|
175
|
+
if (props.devTeam) {
|
|
176
|
+
OneSignalLog_1.OneSignalLog.log('Warning: Both "ios.appleTeamId" and the deprecated "devTeam" plugin prop are set. ' +
|
|
177
|
+
'"devTeam" will be ignored. Remove "devTeam" from your plugin config.');
|
|
178
|
+
}
|
|
179
|
+
return config.ios.appleTeamId;
|
|
180
|
+
}
|
|
181
|
+
if (props.devTeam) {
|
|
182
|
+
OneSignalLog_1.OneSignalLog.log('Warning: The "devTeam" plugin prop is deprecated and will be removed in a future major release. ' +
|
|
183
|
+
'Set "ios.appleTeamId" in your Expo config instead.');
|
|
184
|
+
return props.devTeam;
|
|
185
|
+
}
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
167
188
|
const withOneSignalXcodeProject = (config, props) => {
|
|
168
189
|
return (0, config_plugins_1.withXcodeProject)(config, (newConfig) => {
|
|
169
190
|
const xcodeProject = newConfig.modResults;
|
|
170
191
|
const nseBundleId = `${config.ios?.bundleIdentifier}.${props.nseBundleIdentifier ?? iosConstants_1.NSE_TARGET_NAME}`;
|
|
192
|
+
const devTeam = resolveDevTeam(config, props);
|
|
171
193
|
if (xcodeProject.pbxTargetByName(iosConstants_1.NSE_TARGET_NAME)) {
|
|
172
194
|
OneSignalLog_1.OneSignalLog.log(`${iosConstants_1.NSE_TARGET_NAME} already exists in project. Skipping...`);
|
|
173
195
|
return newConfig;
|
|
@@ -207,7 +229,7 @@ const withOneSignalXcodeProject = (config, props) => {
|
|
|
207
229
|
if (typeof configurations[key].buildSettings !== 'undefined' &&
|
|
208
230
|
configurations[key].buildSettings.PRODUCT_NAME == `"${iosConstants_1.NSE_TARGET_NAME}"`) {
|
|
209
231
|
const buildSettingsObj = configurations[key].buildSettings;
|
|
210
|
-
buildSettingsObj.DEVELOPMENT_TEAM =
|
|
232
|
+
buildSettingsObj.DEVELOPMENT_TEAM = devTeam;
|
|
211
233
|
buildSettingsObj.IPHONEOS_DEPLOYMENT_TARGET =
|
|
212
234
|
props?.iPhoneDeploymentTarget ?? iosConstants_1.IPHONEOS_DEPLOYMENT_TARGET;
|
|
213
235
|
buildSettingsObj.TARGETED_DEVICE_FAMILY = iosConstants_1.TARGETED_DEVICE_FAMILY;
|
|
@@ -216,20 +238,51 @@ const withOneSignalXcodeProject = (config, props) => {
|
|
|
216
238
|
}
|
|
217
239
|
}
|
|
218
240
|
// Add development teams to both your target and the original project
|
|
219
|
-
xcodeProject.addTargetAttribute('DevelopmentTeam',
|
|
220
|
-
xcodeProject.addTargetAttribute('DevelopmentTeam',
|
|
241
|
+
xcodeProject.addTargetAttribute('DevelopmentTeam', devTeam, nseTarget);
|
|
242
|
+
xcodeProject.addTargetAttribute('DevelopmentTeam', devTeam);
|
|
221
243
|
return newConfig;
|
|
222
244
|
});
|
|
223
245
|
};
|
|
246
|
+
const withSoundFiles = (config, onesignalProps) => {
|
|
247
|
+
if (!onesignalProps.sounds) {
|
|
248
|
+
return config;
|
|
249
|
+
}
|
|
250
|
+
return (0, config_plugins_1.withXcodeProject)(config, (config) => {
|
|
251
|
+
const projectRoot = config.modRequest.projectRoot;
|
|
252
|
+
const projectName = config.modRequest.projectName;
|
|
253
|
+
const sourceRoot = config_plugins_1.IOSConfig.Paths.getSourceRoot(projectRoot);
|
|
254
|
+
let project = config.modResults;
|
|
255
|
+
for (const soundFile of onesignalProps.sounds) {
|
|
256
|
+
const fileName = path.basename(soundFile);
|
|
257
|
+
const sourcePath = path.resolve(projectRoot, soundFile);
|
|
258
|
+
const destPath = path.resolve(sourceRoot, fileName);
|
|
259
|
+
OneSignalLog_1.OneSignalLog.log(`Copying sound file ${soundFile} to iOS project`);
|
|
260
|
+
fs.copyFileSync(sourcePath, destPath);
|
|
261
|
+
if (!project.hasFile(`${projectName}/${fileName}`)) {
|
|
262
|
+
project = config_plugins_1.IOSConfig.XcodeUtils.addResourceFileToGroup({
|
|
263
|
+
filepath: `${projectName}/${fileName}`,
|
|
264
|
+
groupName: projectName,
|
|
265
|
+
project,
|
|
266
|
+
isBuildFile: true,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
config.modResults = project;
|
|
271
|
+
return config;
|
|
272
|
+
});
|
|
273
|
+
};
|
|
224
274
|
const withOneSignalIos = (config, props) => {
|
|
225
275
|
config = withAppEnvironment(config, props);
|
|
226
276
|
config = withRemoteNotificationsPermissions(config, props);
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
277
|
+
if (!props.disableNSE) {
|
|
278
|
+
config = withCustomAppGroupsKey(config, props);
|
|
279
|
+
config = withAppGroupPermissions(config, props);
|
|
280
|
+
config = withOneSignalPodfile(config, props);
|
|
281
|
+
config = withOneSignalNSE(config, props);
|
|
282
|
+
config = withOneSignalXcodeProject(config, props);
|
|
283
|
+
config = withEasManagedCredentials(config, props);
|
|
284
|
+
}
|
|
285
|
+
config = withSoundFiles(config, props);
|
|
233
286
|
return config;
|
|
234
287
|
};
|
|
235
288
|
exports.withOneSignalIos = withOneSignalIos;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileManager contains static *awaitable* file-system functions
|
|
3
|
+
*/
|
|
4
|
+
export declare class FileManager {
|
|
5
|
+
static readFile(path: string): Promise<string>;
|
|
6
|
+
static writeFile(path: string, contents: string): Promise<void>;
|
|
7
|
+
static copyFile(path1: string, path2: string): Promise<void>;
|
|
8
|
+
static dirExists(path: string): boolean;
|
|
9
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export default class NseUpdaterManager {
|
|
2
|
+
private nsePath;
|
|
3
|
+
constructor(iosPath: string);
|
|
4
|
+
updateNSEEntitlements(groupIdentifier: string): Promise<void>;
|
|
5
|
+
updateNSEBundleVersion(version: string): Promise<void>;
|
|
6
|
+
updateNSEBundleShortVersion(version: string): Promise<void>;
|
|
7
|
+
updateNSEInfoPlistAppGroupKey(appGroupName: string): Promise<void>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a hex color string (#RGB, #RRGGBB, or #AARRGGBB) to an
|
|
3
|
+
* 8-character ARGB hex string (no '#') expected by the OneSignal Android SDK.
|
|
4
|
+
*/
|
|
5
|
+
export declare function parseColorToARGB(color: string): string;
|
|
6
|
+
export declare function validatePluginProps(props: any): void;
|
|
7
|
+
export declare function getAppGroupIdentifier(bundleIdentifier: string, customAppGroupName?: string): string;
|
package/build/support/helpers.js
CHANGED
|
@@ -1,8 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseColorToARGB = parseColorToARGB;
|
|
3
4
|
exports.validatePluginProps = validatePluginProps;
|
|
4
5
|
exports.getAppGroupIdentifier = getAppGroupIdentifier;
|
|
6
|
+
const path_1 = require("path");
|
|
5
7
|
const types_1 = require("../types/types");
|
|
8
|
+
const HEX_COLOR_6_REGEX = /^#?[0-9A-Fa-f]{6}$/;
|
|
9
|
+
const HEX_COLOR_8_REGEX = /^#?[0-9A-Fa-f]{8}$/;
|
|
10
|
+
/**
|
|
11
|
+
* Converts a hex color string (#RGB, #RRGGBB, or #AARRGGBB) to an
|
|
12
|
+
* 8-character ARGB hex string (no '#') expected by the OneSignal Android SDK.
|
|
13
|
+
*/
|
|
14
|
+
function parseColorToARGB(color) {
|
|
15
|
+
const hex = color.replace('#', '');
|
|
16
|
+
if (HEX_COLOR_8_REGEX.test(hex)) {
|
|
17
|
+
return hex.toUpperCase();
|
|
18
|
+
}
|
|
19
|
+
if (HEX_COLOR_6_REGEX.test(hex)) {
|
|
20
|
+
return `FF${hex.toUpperCase()}`;
|
|
21
|
+
}
|
|
22
|
+
if (/^[0-9A-Fa-f]{3}$/.test(hex)) {
|
|
23
|
+
const expanded = hex
|
|
24
|
+
.split('')
|
|
25
|
+
.map((c) => c + c)
|
|
26
|
+
.join('');
|
|
27
|
+
return `FF${expanded.toUpperCase()}`;
|
|
28
|
+
}
|
|
29
|
+
throw new Error(`OneSignal Expo Plugin: 'smallIconAccentColor' must be a valid hex color (e.g. "#FF0000"), got "${color}".`);
|
|
30
|
+
}
|
|
6
31
|
function validatePluginProps(props) {
|
|
7
32
|
// check the type of each property
|
|
8
33
|
if (typeof props.mode !== 'string') {
|
|
@@ -18,9 +43,11 @@ function validatePluginProps(props) {
|
|
|
18
43
|
if (props.smallIcons && !Array.isArray(props.smallIcons)) {
|
|
19
44
|
throw new Error("OneSignal Expo Plugin: 'smallIcons' must be an array.");
|
|
20
45
|
}
|
|
21
|
-
if (props.smallIconAccentColor
|
|
22
|
-
typeof props.smallIconAccentColor !== 'string') {
|
|
23
|
-
|
|
46
|
+
if (props.smallIconAccentColor != null) {
|
|
47
|
+
if (typeof props.smallIconAccentColor !== 'string') {
|
|
48
|
+
throw new Error("OneSignal Expo Plugin: 'smallIconAccentColor' must be a string.");
|
|
49
|
+
}
|
|
50
|
+
parseColorToARGB(props.smallIconAccentColor);
|
|
24
51
|
}
|
|
25
52
|
if (props.largeIcons && !Array.isArray(props.largeIcons)) {
|
|
26
53
|
throw new Error("OneSignal Expo Plugin: 'largeIcons' must be an array.");
|
|
@@ -35,6 +62,22 @@ function validatePluginProps(props) {
|
|
|
35
62
|
typeof props.nseBundleIdentifier !== 'string') {
|
|
36
63
|
throw new Error("OneSignal Expo Plugin: 'nseBundleIdentifier' must be a string.");
|
|
37
64
|
}
|
|
65
|
+
if (props.disableNSE !== undefined && typeof props.disableNSE !== 'boolean') {
|
|
66
|
+
throw new Error("OneSignal Expo Plugin: 'disableNSE' must be a boolean.");
|
|
67
|
+
}
|
|
68
|
+
if (props.sounds !== undefined) {
|
|
69
|
+
if (!Array.isArray(props.sounds)) {
|
|
70
|
+
throw new Error("OneSignal Expo Plugin: 'sounds' must be an array.");
|
|
71
|
+
}
|
|
72
|
+
for (const sound of props.sounds) {
|
|
73
|
+
if (typeof sound !== 'string') {
|
|
74
|
+
throw new Error("OneSignal Expo Plugin: each entry in 'sounds' must be a string path.");
|
|
75
|
+
}
|
|
76
|
+
if ((0, path_1.extname)(sound).toLowerCase() !== '.wav') {
|
|
77
|
+
throw new Error(`OneSignal Expo Plugin: sound file "${sound}" must be a .wav file. Only .wav is supported (works on both iOS and Android).`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
38
81
|
// check for extra properties
|
|
39
82
|
const inputProps = Object.keys(props);
|
|
40
83
|
for (const prop of inputProps) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const IPHONEOS_DEPLOYMENT_TARGET = "11.0";
|
|
2
|
+
export declare const TARGETED_DEVICE_FAMILY = "\"1,2\"";
|
|
3
|
+
export declare const GROUP_IDENTIFIER_TEMPLATE_REGEX: RegExp;
|
|
4
|
+
export declare const BUNDLE_SHORT_VERSION_TEMPLATE_REGEX: RegExp;
|
|
5
|
+
export declare const BUNDLE_VERSION_TEMPLATE_REGEX: RegExp;
|
|
6
|
+
export declare const DEFAULT_BUNDLE_VERSION = "1";
|
|
7
|
+
export declare const DEFAULT_BUNDLE_SHORT_VERSION = "1.0";
|
|
8
|
+
export declare const NSE_TARGET_NAME = "OneSignalNotificationServiceExtension";
|
|
9
|
+
export declare const NSE_SOURCE_FILE = "NotificationService.m";
|
|
10
|
+
export declare const NSE_PODFILE_SNIPPET = "\ntarget 'OneSignalNotificationServiceExtension' do\n pod 'OneSignalXCFramework', '>= 5.0', '< 6.0'\n use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']\nend";
|
|
11
|
+
export declare const NSE_PODFILE_REGEX: RegExp;
|
|
12
|
+
export declare const NSE_EXT_FILES: string[];
|
|
@@ -4,26 +4,31 @@
|
|
|
4
4
|
|
|
5
5
|
@interface NotificationService ()
|
|
6
6
|
|
|
7
|
-
@property
|
|
8
|
-
|
|
9
|
-
@property
|
|
7
|
+
@property(nonatomic, strong) void (^contentHandler)
|
|
8
|
+
(UNNotificationContent *contentToDeliver);
|
|
9
|
+
@property(nonatomic, strong) UNNotificationRequest *receivedRequest;
|
|
10
|
+
@property(nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
|
|
10
11
|
|
|
11
12
|
@end
|
|
12
13
|
|
|
13
14
|
@implementation NotificationService
|
|
14
15
|
|
|
15
|
-
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request
|
|
17
|
+
withContentHandler:
|
|
18
|
+
(void (^)(UNNotificationContent *_Nonnull))
|
|
19
|
+
contentHandler {
|
|
20
|
+
self.receivedRequest = request;
|
|
21
|
+
self.contentHandler = contentHandler;
|
|
22
|
+
self.bestAttemptContent = [request.content mutableCopy];
|
|
23
|
+
[OneSignal didReceiveNotificationExtensionRequest:self.receivedRequest
|
|
24
|
+
withMutableNotificationContent:self.bestAttemptContent
|
|
25
|
+
withContentHandler:self.contentHandler];
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
- (void)serviceExtensionTimeWillExpire {
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
[OneSignal serviceExtensionTimeWillExpireRequest:self.receivedRequest
|
|
30
|
+
withMutableNotificationContent:self.bestAttemptContent];
|
|
31
|
+
self.contentHandler(self.bestAttemptContent);
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
@end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function updatePodfile(iosPath: string): Promise<void>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OneSignalPluginProps refer to the properties set by the user in their app config file (e.g: app.json)
|
|
3
|
+
*/
|
|
4
|
+
export type OneSignalPluginProps = {
|
|
5
|
+
/**
|
|
6
|
+
* (required) Used to configure APNs environment entitlement. "development" or "production"
|
|
7
|
+
*/
|
|
8
|
+
mode: 'development' | 'production';
|
|
9
|
+
/**
|
|
10
|
+
* (optional) Used to configure Apple Team ID. You can find your Apple Team ID by running expo credentials:manager e.g: "91SW8A37CR"
|
|
11
|
+
* @deprecated Use `ios.appleTeamId` in your Expo config instead. This prop will be removed in a future major release.
|
|
12
|
+
*/
|
|
13
|
+
devTeam?: string;
|
|
14
|
+
/**
|
|
15
|
+
* (optional) Target IPHONEOS_DEPLOYMENT_TARGET value to be used when adding the iOS NSE. A deployment target is nothing more than
|
|
16
|
+
* the minimum version of the operating system the application can run on. This value should match the value in your Podfile e.g: "12.0".
|
|
17
|
+
*/
|
|
18
|
+
iPhoneDeploymentTarget?: string;
|
|
19
|
+
/**
|
|
20
|
+
* (optional) The small notification icons for Android. Images will be automatically scaled up/down, the recommended size
|
|
21
|
+
* is 96x96 to always scale down.
|
|
22
|
+
*/
|
|
23
|
+
smallIcons?: string[];
|
|
24
|
+
/**
|
|
25
|
+
* (optional) The accent color to use for notification icons on Android. Must be a valid Android color resource, for example: "#FF0000"
|
|
26
|
+
*/
|
|
27
|
+
smallIconAccentColor?: string;
|
|
28
|
+
/**
|
|
29
|
+
* (optional) The large notification icons for Android. Images will be automatically scaled up/down to 256x256.
|
|
30
|
+
*/
|
|
31
|
+
largeIcons?: string[];
|
|
32
|
+
/**
|
|
33
|
+
* (optional) The local path to a custom Notification Service Extension (NSE), written in Objective-C. The NSE will typically start as a copy
|
|
34
|
+
* of the default NSE found at (support/serviceExtensionFiles/NotificationService.m, then altered to support any custom
|
|
35
|
+
* logic required.
|
|
36
|
+
*/
|
|
37
|
+
iosNSEFilePath?: string;
|
|
38
|
+
/**
|
|
39
|
+
* (optional) Used to configure a custom iOS app group name. If not provided, defaults to "group.{ios.bundleIdentifier}.onesignal".
|
|
40
|
+
* @see https://documentation.onesignal.com/docs/ios-sdk-setup#step-3-create-an-app-group
|
|
41
|
+
*/
|
|
42
|
+
appGroupName?: string;
|
|
43
|
+
/**
|
|
44
|
+
* (optional) Used to configure a custom bundle identifier suffix for the iOS Notification Service Extension.
|
|
45
|
+
* The full bundle identifier will be "{ios.bundleIdentifier}.{nseBundleIdentifier}".
|
|
46
|
+
* If not provided, defaults to "OneSignalNotificationServiceExtension".
|
|
47
|
+
*/
|
|
48
|
+
nseBundleIdentifier?: string;
|
|
49
|
+
/**
|
|
50
|
+
* (optional) If true, the iOS Notification Service Extension (NSE) will not be added to the project.
|
|
51
|
+
* The NSE is required for badges, confirmed delivery, media attachments, and action buttons.
|
|
52
|
+
* Only disable if you only need basic push notifications.
|
|
53
|
+
*/
|
|
54
|
+
disableNSE?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* (optional) An array of local paths to custom notification sound files (.wav only).
|
|
57
|
+
* Files are added to the iOS app bundle and Android res/raw/.
|
|
58
|
+
* @see https://documentation.onesignal.com/docs/customize-notification-sounds
|
|
59
|
+
*/
|
|
60
|
+
sounds?: string[];
|
|
61
|
+
};
|
|
62
|
+
export declare const ONESIGNAL_PLUGIN_PROPS: string[];
|
package/build/types/types.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.ONESIGNAL_PLUGIN_PROPS = void 0;
|
|
4
4
|
exports.ONESIGNAL_PLUGIN_PROPS = [
|
|
5
5
|
'mode',
|
|
6
6
|
'devTeam',
|
|
@@ -11,9 +11,6 @@ exports.ONESIGNAL_PLUGIN_PROPS = [
|
|
|
11
11
|
'smallIconAccentColor',
|
|
12
12
|
'appGroupName',
|
|
13
13
|
'nseBundleIdentifier',
|
|
14
|
+
'disableNSE',
|
|
15
|
+
'sounds',
|
|
14
16
|
];
|
|
15
|
-
var Mode;
|
|
16
|
-
(function (Mode) {
|
|
17
|
-
Mode["Dev"] = "development";
|
|
18
|
-
Mode["Prod"] = "production";
|
|
19
|
-
})(Mode || (exports.Mode = Mode = {}));
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "onesignal-expo-plugin",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Some Changez",
|
|
5
5
|
"main": "./app.plugin.js",
|
|
6
|
+
"types": "./build/types/types.d.ts",
|
|
6
7
|
"files": [
|
|
7
8
|
"build",
|
|
8
9
|
"app.plugin.js"
|
|
@@ -10,11 +11,15 @@
|
|
|
10
11
|
"scripts": {
|
|
11
12
|
"test": "bun test",
|
|
12
13
|
"test:coverage": "bun test --coverage",
|
|
13
|
-
"build": "
|
|
14
|
-
"format:
|
|
15
|
-
"format:
|
|
14
|
+
"build": "rm -rf build && tsc && cp -a src/support/serviceExtensionFiles build/support/",
|
|
15
|
+
"format:spotless": "./examples/demo/android/gradlew spotlessApply",
|
|
16
|
+
"format:prettier": "prettier --write \"**/*.{ts,tsx}\" --ignore-path .gitignore",
|
|
17
|
+
"format": "concurrently \"bun run format:spotless\" \"bun run format:prettier\"",
|
|
18
|
+
"format:check:spotless": "./examples/demo/android/gradlew spotlessCheck",
|
|
19
|
+
"format:check:prettier": "prettier --check \"**/*.{ts,tsx}\" --ignore-path .gitignore",
|
|
20
|
+
"format:check": "concurrently \"bun run format:check:spotless\" \"bun run format:check:prettier\"",
|
|
16
21
|
"lint": "oxlint src examples && bun run format:check",
|
|
17
|
-
"lint:fix": "oxlint src examples --fix && bun run format
|
|
22
|
+
"lint:fix": "oxlint src examples --fix && bun run format"
|
|
18
23
|
},
|
|
19
24
|
"repository": {
|
|
20
25
|
"type": "git",
|
|
@@ -42,6 +47,7 @@
|
|
|
42
47
|
"homepage": "https://github.com/OneSignal/onesignal-expo-plugin#readme",
|
|
43
48
|
"devDependencies": {
|
|
44
49
|
"@types/bun": "^1.3.9",
|
|
50
|
+
"concurrently": "^9.2.1",
|
|
45
51
|
"expo-module-scripts": "^5.0.8",
|
|
46
52
|
"oxlint": "^1.43.0",
|
|
47
53
|
"prettier": "^3.8.1",
|