From 582bbcd5480efb32a0a74f12e4366d77c5b56b12 Mon Sep 17 00:00:00 2001 From: Jakov Glavina Date: Sat, 22 Apr 2023 18:57:08 +0200 Subject: [PATCH 01/11] chore: update withConfig.ts --- plugin/src/withConfig.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/plugin/src/withConfig.ts b/plugin/src/withConfig.ts index 7acce0c..6c38330 100644 --- a/plugin/src/withConfig.ts +++ b/plugin/src/withConfig.ts @@ -5,13 +5,11 @@ export const withConfig: ConfigPlugin<{ targetName: string; }> = (config, { bundleIdentifier, targetName }) => { 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 +23,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 +38,9 @@ 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]; - appClipConfig.entitlements = {}; + widgetsExtensionConfig.entitlements = {}; } return config; From 02ef28f43bd4b88414f0ba8dcb40d50262b75971 Mon Sep 17 00:00:00 2001 From: Jakov Glavina Date: Sat, 22 Apr 2023 19:05:22 +0200 Subject: [PATCH 02/11] feat: setting widget extension entitlements - WIP --- .../src/lib/getWidgetExtensionEntitlements.ts | 26 ++++++++++++++++++ plugin/src/withConfig.ts | 19 +++++++++++-- plugin/src/withWidgetExtensionEntitlements.ts | 27 +++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 plugin/src/lib/getWidgetExtensionEntitlements.ts create mode 100644 plugin/src/withWidgetExtensionEntitlements.ts diff --git a/plugin/src/lib/getWidgetExtensionEntitlements.ts b/plugin/src/lib/getWidgetExtensionEntitlements.ts new file mode 100644 index 0000000..77dd375 --- /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 6c38330..2e36b42 100644 --- a/plugin/src/withConfig.ts +++ b/plugin/src/withConfig.ts @@ -1,9 +1,12 @@ 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) { @@ -40,7 +43,19 @@ export const withConfig: ConfigPlugin<{ if (configIndex != null && config.extra) { const widgetsExtensionConfig = config.extra.eas.build.experimental.ios.appExtensions[configIndex]; - widgetsExtensionConfig.entitlements = {}; + widgetsExtensionConfig.entitlements = { + ...widgetsExtensionConfig.entitlements, + ...getWidgetExtensionEntitlements(config.ios, { + groupIdentifier, + }), + }; + + config.ios = { + ...config.ios, + entitlements: { + ...addApplicationGroupsEntitlement(config.ios?.entitlements ?? {}, groupIdentifier), + }, + }; } return config; diff --git a/plugin/src/withWidgetExtensionEntitlements.ts b/plugin/src/withWidgetExtensionEntitlements.ts new file mode 100644 index 0000000..2f60eb9 --- /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 withAppClipEntitlements: 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; + }); +}; From fcfb990cfe740fb070928ae3f1e83f1116ac3bd4 Mon Sep 17 00:00:00 2001 From: Jakov Glavina Date: Sat, 22 Apr 2023 19:08:14 +0200 Subject: [PATCH 03/11] feat: widget extension entitlements --- plugin/src/index.ts | 15 ++++++++------- plugin/src/withWidgetExtensionEntitlements.ts | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/plugin/src/index.ts b/plugin/src/index.ts index 25d36cd..9c5be51 100644 --- a/plugin/src/index.ts +++ b/plugin/src/index.ts @@ -3,14 +3,14 @@ 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; -}> = (config, { frequentUpdates = false, widgetsFolder = "widgets" }) => { - const targetName = `${IOSConfig.XcodeUtils.sanitizedName( - config.name - )}Widgets`; + groupIdentifier?: string; +}> = (config, { frequentUpdates = false, widgetsFolder = "widgets", groupIdentifier }) => { + const targetName = `${IOSConfig.XcodeUtils.sanitizedName(config.name)}Widgets`; const bundleIdentifier = `${config.ios?.bundleIdentifier}.${targetName}`; const deploymentTarget = "16.2"; @@ -33,11 +33,12 @@ const withLiveActivities: ConfigPlugin<{ widgetsFolder, }, ], + [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/withWidgetExtensionEntitlements.ts b/plugin/src/withWidgetExtensionEntitlements.ts index 2f60eb9..d1807e1 100644 --- a/plugin/src/withWidgetExtensionEntitlements.ts +++ b/plugin/src/withWidgetExtensionEntitlements.ts @@ -5,7 +5,7 @@ import * as path from "path"; import { getWidgetExtensionEntitlements } from "./lib/getWidgetExtensionEntitlements"; -export const withAppClipEntitlements: ConfigPlugin<{ +export const withWidgetExtensionEntitlements: ConfigPlugin<{ targetName: string; targetPath: string; groupIdentifier: string; From 6c788a2cdb5910c83e39d35dd3c4ea42d3b1a202 Mon Sep 17 00:00:00 2001 From: Jakov Glavina Date: Sat, 22 Apr 2023 19:27:01 +0200 Subject: [PATCH 04/11] chore: update readme --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c37e6f..359e2f8 100644 --- a/README.md +++ b/README.md @@ -16,12 +16,16 @@ And add the following config to app.json (where widgetsFolder is the path to the "plugins": [ [ "react-native-widget-extension", - { frequentUpdates: true, widgetsFolder: "PizzaDeliveryWidgets" }, + { "frequentUpdates": true, "widgetsFolder": "PizzaDeliveryWidgets", "groupIdentifier": "group.my.app.groupName" }, ], ] } ``` +It is highly recommended to specify the `groupIdentifier` since it assigns both the main app target and the widget target to the same app group +which enables you to more easily communicate between the widget and the main app. Do note that the `groupIdentifier` **must** start with `group.` +as it is a requirement imposed by Apple. + Then in React land, you can use the following: ```typescript From 8177d0d9d7cd755b899ba085273014dddc611b88 Mon Sep 17 00:00:00 2001 From: Jakov Glavina Date: Sat, 22 Apr 2023 19:35:41 +0200 Subject: [PATCH 05/11] chore: add entitlements to pbx group --- plugin/src/xcode/addPbxGroup.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugin/src/xcode/addPbxGroup.ts b/plugin/src/xcode/addPbxGroup.ts index ca8e413..683fc96 100644 --- a/plugin/src/xcode/addPbxGroup.ts +++ b/plugin/src/xcode/addPbxGroup.ts @@ -12,12 +12,11 @@ export function addPbxGroup( widgetFiles: WidgetFiles; } ) { - const { swiftFiles, assetDirectories, entitlementFiles, plistFiles } = - widgetFiles; + const { swiftFiles, assetDirectories, entitlementFiles, plistFiles } = widgetFiles; // Add PBX group const { uuid: pbxGroupUuid } = xcodeProject.addPbxGroup( - [...swiftFiles, ...entitlementFiles, ...plistFiles, ...assetDirectories], + [...swiftFiles, ...entitlementFiles, ...plistFiles, ...assetDirectories, `${targetName}.entitlements`], targetName, targetName ); From f49144bc59398daa0ba19cad7e8d173133b76111 Mon Sep 17 00:00:00 2001 From: Nathan Ahn Date: Tue, 10 Dec 2024 20:19:18 -0500 Subject: [PATCH 06/11] Version increment --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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", From 6cd8d46bf62a7da242dd854c620bec4b95c4b344 Mon Sep 17 00:00:00 2001 From: Nathan Ahn Date: Tue, 10 Dec 2024 20:26:20 -0500 Subject: [PATCH 07/11] Adding code sign entitlements --- plugin/src/xcode/addXCConfigurationList.ts | 1 + 1 file changed, 1 insertion(+) 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"`, }; From 3e1ba327338d20b82e3fe00cff8c934e4b6bdcbb Mon Sep 17 00:00:00 2001 From: Nathan Ahn Date: Tue, 10 Dec 2024 20:27:20 -0500 Subject: [PATCH 08/11] Import fix --- plugin/src/lib/getWidgetExtensionEntitlements.ts | 2 +- plugin/src/withWidgetExtensionEntitlements.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/src/lib/getWidgetExtensionEntitlements.ts b/plugin/src/lib/getWidgetExtensionEntitlements.ts index 77dd375..f6160a6 100644 --- a/plugin/src/lib/getWidgetExtensionEntitlements.ts +++ b/plugin/src/lib/getWidgetExtensionEntitlements.ts @@ -1,4 +1,4 @@ -import { ExportedConfig, InfoPlist } from "expo/config-plugins"; +import { ExportedConfig, InfoPlist } from "@expo/config-plugins"; export function getWidgetExtensionEntitlements( iosConfig: ExportedConfig["ios"], diff --git a/plugin/src/withWidgetExtensionEntitlements.ts b/plugin/src/withWidgetExtensionEntitlements.ts index d1807e1..7ea5db0 100644 --- a/plugin/src/withWidgetExtensionEntitlements.ts +++ b/plugin/src/withWidgetExtensionEntitlements.ts @@ -1,5 +1,5 @@ import plist from "@expo/plist"; -import { ConfigPlugin, withInfoPlist } from "expo/config-plugins"; +import { ConfigPlugin, withInfoPlist } from "@expo/config-plugins"; import * as fs from "fs"; import * as path from "path"; From 21fb1226430ed9023f4951747fa4093c74b0f20d Mon Sep 17 00:00:00 2001 From: Nathan Ahn Date: Tue, 10 Dec 2024 20:31:39 -0500 Subject: [PATCH 09/11] Readme update --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index 61cef12..e61d870 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,6 @@ And add the following config to app.json (where widgetsFolder is the path to the } ``` -It is highly recommended to specify the `groupIdentifier` since it assigns both the main app target and the widget target to the same app group -which enables you to more easily communicate between the widget and the main app. Do note that the `groupIdentifier` **must** start with `group.` -as it is a requirement imposed by Apple. - Then in React land, you can use the following: ```typescript @@ -44,6 +40,7 @@ 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 From c08ad5a69d76ab13e0ee8b41946c459e4edcfdea Mon Sep 17 00:00:00 2001 From: Nathan Ahn Date: Tue, 10 Dec 2024 21:29:28 -0500 Subject: [PATCH 11/11] Sentry build fix --- plugin/src/withPodfile.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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: