diff --git a/README.md b/README.md index 255c4b7..05640fc 100644 --- a/README.md +++ b/README.md @@ -40,9 +40,10 @@ startActivity(3, "4343", "$32.23", driverName, 47, 43); - `frequentUpdates` (boolean, default: false): Depending on this param, NSSupportsLiveActivitiesFrequentUpdates will be set - `widgetsFolder` (string, default: "widgets"): Path from the project root to the folder containing the Swift widget files - `deploymentTarget` (string, default: "16.2"): The minimum deployment target for the app +- `groupIdentifier` (string): The app group identifier which is required for communication with the main app. Must start with `group.` ## Example diff --git a/package.json b/package.json index 9b30bf0..43a69b1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-widget-extension", - "version": "0.0.5", + "version": "0.0.6", "description": "Expo config plugin to add widgets and live activities to a React Native app", "main": "build/index.js", "types": "build/index.d.ts", diff --git a/plugin/src/index.ts b/plugin/src/index.ts index 16e703f..a22aeca 100644 --- a/plugin/src/index.ts +++ b/plugin/src/index.ts @@ -3,13 +3,15 @@ import { withConfig } from "./withConfig"; import { withPodfile } from "./withPodfile"; import { withXcode } from "./withXcode"; +import { withWidgetExtensionEntitlements } from "./withWidgetExtensionEntitlements"; -const withLiveActivities: ConfigPlugin<{ +const withWidgetsAndLiveActivities: ConfigPlugin<{ frequentUpdates?: boolean; widgetsFolder?: string; deploymentTarget?: string; moduleFileName?: string; attributesFileName?: string; + groupIdentifier?: string; }> = ( config, { @@ -18,6 +20,7 @@ const withLiveActivities: ConfigPlugin<{ deploymentTarget = "16.2", moduleFileName = "Module.swift", attributesFileName = "Attributes.swift", + groupIdentifier, } ) => { const targetName = `${IOSConfig.XcodeUtils.sanitizedName( @@ -46,11 +49,12 @@ const withLiveActivities: ConfigPlugin<{ attributesFileName, }, ], + [withWidgetExtensionEntitlements, { targetName, groupIdentifier }], [withPodfile, { targetName }], - [withConfig, { targetName, bundleIdentifier }], + [withConfig, { targetName, bundleIdentifier, groupIdentifier }], ]); return config; }; -export default withLiveActivities; +export default withWidgetsAndLiveActivities; diff --git a/plugin/src/lib/getWidgetExtensionEntitlements.ts b/plugin/src/lib/getWidgetExtensionEntitlements.ts new file mode 100644 index 0000000..f6160a6 --- /dev/null +++ b/plugin/src/lib/getWidgetExtensionEntitlements.ts @@ -0,0 +1,26 @@ +import { ExportedConfig, InfoPlist } from "@expo/config-plugins"; + +export function getWidgetExtensionEntitlements( + iosConfig: ExportedConfig["ios"], + { + groupIdentifier, + }: { + groupIdentifier?: string; + } +) { + const entitlements: InfoPlist = {}; + + addApplicationGroupsEntitlement(entitlements, groupIdentifier); + + return entitlements; +} + +export function addApplicationGroupsEntitlement(entitlements: InfoPlist, groupIdentifier?: string) { + if (groupIdentifier) { + const existingApplicationGroups = (entitlements["com.apple.security.application-groups"] as string[]) ?? []; + + entitlements["com.apple.security.application-groups"] = [groupIdentifier, ...existingApplicationGroups]; + } + + return entitlements; +} diff --git a/plugin/src/withConfig.ts b/plugin/src/withConfig.ts index 3861d27..dbf5dae 100644 --- a/plugin/src/withConfig.ts +++ b/plugin/src/withConfig.ts @@ -1,17 +1,18 @@ import { ConfigPlugin } from "@expo/config-plugins"; +import { addApplicationGroupsEntitlement, getWidgetExtensionEntitlements } from "./lib/getWidgetExtensionEntitlements"; + export const withConfig: ConfigPlugin<{ bundleIdentifier: string; targetName: string; -}> = (config, { bundleIdentifier, targetName }) => { + groupIdentifier?: string; +}> = (config, { bundleIdentifier, targetName, groupIdentifier }) => { let configIndex: null | number = null; - config.extra?.eas?.build?.experimental?.ios?.appExtensions?.forEach( - (ext: any, index: number) => { - if (ext.targetName === targetName) { - configIndex = index; - } + config.extra?.eas?.build?.experimental?.ios?.appExtensions?.forEach((ext: any, index: number) => { + if (ext.targetName === targetName) { + configIndex = index; } - ); + }); if (!configIndex) { config.extra = { @@ -25,8 +26,7 @@ export const withConfig: ConfigPlugin<{ ios: { ...config.extra?.eas?.build?.experimental?.ios, appExtensions: [ - ...(config.extra?.eas?.build?.experimental?.ios - ?.appExtensions ?? []), + ...(config.extra?.eas?.build?.experimental?.ios?.appExtensions ?? []), { targetName, bundleIdentifier, @@ -41,10 +41,21 @@ export const withConfig: ConfigPlugin<{ } if (configIndex != null && config.extra) { - const appClipConfig = - config.extra.eas.build.experimental.ios.appExtensions[configIndex]; + const widgetsExtensionConfig = config.extra.eas.build.experimental.ios.appExtensions[configIndex]; + + widgetsExtensionConfig.entitlements = { + ...widgetsExtensionConfig.entitlements, + ...getWidgetExtensionEntitlements(config.ios, { + groupIdentifier, + }), + }; - appClipConfig.entitlements = {}; + config.ios = { + ...config.ios, + entitlements: { + ...addApplicationGroupsEntitlement(config.ios?.entitlements ?? {}, groupIdentifier), + }, + }; } return config; diff --git a/plugin/src/withPodfile.ts b/plugin/src/withPodfile.ts index 6c4a712..c45b5a7 100644 --- a/plugin/src/withPodfile.ts +++ b/plugin/src/withPodfile.ts @@ -35,7 +35,8 @@ export const withPodfile: ConfigPlugin<{ targetName: string }> = ( src: podFileContent, newSrc: `installer.pods_project.targets.each do |target| target.build_configurations.each do |config| - config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'No' + # Sentry has build errors unless configured as 'YES' for the Sentry target: https://github.com/bndkt/react-native-widget-extension/issues/24 + config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = target.name == 'Sentry' ? 'YES' : 'No' end end`, anchor: diff --git a/plugin/src/withWidgetExtensionEntitlements.ts b/plugin/src/withWidgetExtensionEntitlements.ts new file mode 100644 index 0000000..7ea5db0 --- /dev/null +++ b/plugin/src/withWidgetExtensionEntitlements.ts @@ -0,0 +1,27 @@ +import plist from "@expo/plist"; +import { ConfigPlugin, withInfoPlist } from "@expo/config-plugins"; +import * as fs from "fs"; +import * as path from "path"; + +import { getWidgetExtensionEntitlements } from "./lib/getWidgetExtensionEntitlements"; + +export const withWidgetExtensionEntitlements: ConfigPlugin<{ + targetName: string; + targetPath: string; + groupIdentifier: string; + appleSignin: boolean; +}> = (config, { targetName, groupIdentifier }) => { + return withInfoPlist(config, (config) => { + const targetPath = path.join(config.modRequest.platformProjectRoot, targetName); + const filePath = path.join(targetPath, `${targetName}.entitlements`); + + const appClipEntitlements = getWidgetExtensionEntitlements(config.ios, { + groupIdentifier, + }); + + fs.mkdirSync(path.dirname(filePath), { recursive: true }); + fs.writeFileSync(filePath, plist.build(appClipEntitlements)); + + return config; + }); +}; diff --git a/plugin/src/xcode/addPbxGroup.ts b/plugin/src/xcode/addPbxGroup.ts index a6df71c..77061ac 100644 --- a/plugin/src/xcode/addPbxGroup.ts +++ b/plugin/src/xcode/addPbxGroup.ts @@ -30,6 +30,7 @@ export function addPbxGroup( ...entitlementFiles, ...plistFiles, ...assetDirectories, + `${targetName}.entitlements`, ], targetName, targetName diff --git a/plugin/src/xcode/addXCConfigurationList.ts b/plugin/src/xcode/addXCConfigurationList.ts index ded415b..2de995a 100644 --- a/plugin/src/xcode/addXCConfigurationList.ts +++ b/plugin/src/xcode/addXCConfigurationList.ts @@ -52,6 +52,7 @@ export function addXCConfigurationList( INFOPLIST_KEY_NSHumanReadableCopyright: `""`, MARKETING_VERSION: `"${marketingVersion}"`, SWIFT_OPTIMIZATION_LEVEL: `"-Onone"`, + CODE_SIGN_ENTITLEMENTS: `"${targetName}/${targetName}.entitlements"`, // DEVELOPMENT_TEAM: `"G76836P2D4"`, };