@trentrand/react-native-app-clip 0.6.2-beta.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.
Files changed (96) hide show
  1. package/README.md +132 -0
  2. package/app.plugin.js +1 -0
  3. package/build/ReactNativeAppClipModule/ReactNativeAppClipModule.d.ts +4 -0
  4. package/build/ReactNativeAppClipModule/ReactNativeAppClipModule.d.ts.map +1 -0
  5. package/build/ReactNativeAppClipModule/ReactNativeAppClipModule.ios.d.ts +4 -0
  6. package/build/ReactNativeAppClipModule/ReactNativeAppClipModule.ios.d.ts.map +1 -0
  7. package/build/ReactNativeAppClipModule/ReactNativeAppClipModule.ios.js +5 -0
  8. package/build/ReactNativeAppClipModule/ReactNativeAppClipModule.ios.js.map +1 -0
  9. package/build/ReactNativeAppClipModule/ReactNativeAppClipModule.js +15 -0
  10. package/build/ReactNativeAppClipModule/ReactNativeAppClipModule.js.map +1 -0
  11. package/build/ReactNativeAppClipModule/index.d.ts +3 -0
  12. package/build/ReactNativeAppClipModule/index.d.ts.map +1 -0
  13. package/build/ReactNativeAppClipModule/index.js +3 -0
  14. package/build/ReactNativeAppClipModule/index.js.map +1 -0
  15. package/build/ReactNativeAppClipModule/types.d.ts +9 -0
  16. package/build/ReactNativeAppClipModule/types.d.ts.map +1 -0
  17. package/build/ReactNativeAppClipModule/types.js +2 -0
  18. package/build/ReactNativeAppClipModule/types.js.map +1 -0
  19. package/build/getBundleIdentifier/getBundleIdentifier.d.ts +4 -0
  20. package/build/getBundleIdentifier/getBundleIdentifier.d.ts.map +1 -0
  21. package/build/getBundleIdentifier/getBundleIdentifier.ios.d.ts +4 -0
  22. package/build/getBundleIdentifier/getBundleIdentifier.ios.d.ts.map +1 -0
  23. package/build/getBundleIdentifier/getBundleIdentifier.ios.js +11 -0
  24. package/build/getBundleIdentifier/getBundleIdentifier.ios.js.map +1 -0
  25. package/build/getBundleIdentifier/getBundleIdentifier.js +5 -0
  26. package/build/getBundleIdentifier/getBundleIdentifier.js.map +1 -0
  27. package/build/getBundleIdentifier/index.d.ts +3 -0
  28. package/build/getBundleIdentifier/index.d.ts.map +1 -0
  29. package/build/getBundleIdentifier/index.js +3 -0
  30. package/build/getBundleIdentifier/index.js.map +1 -0
  31. package/build/getBundleIdentifier/types.d.ts +2 -0
  32. package/build/getBundleIdentifier/types.d.ts.map +1 -0
  33. package/build/getBundleIdentifier/types.js +2 -0
  34. package/build/getBundleIdentifier/types.js.map +1 -0
  35. package/build/index.d.ts +15 -0
  36. package/build/index.d.ts.map +1 -0
  37. package/build/index.js +23 -0
  38. package/build/index.js.map +1 -0
  39. package/build/isClip/index.d.ts +3 -0
  40. package/build/isClip/index.d.ts.map +1 -0
  41. package/build/isClip/index.js +3 -0
  42. package/build/isClip/index.js.map +1 -0
  43. package/build/isClip/isClip.clip.d.ts +9 -0
  44. package/build/isClip/isClip.clip.d.ts.map +1 -0
  45. package/build/isClip/isClip.clip.js +10 -0
  46. package/build/isClip/isClip.clip.js.map +1 -0
  47. package/build/isClip/isClip.d.ts +4 -0
  48. package/build/isClip/isClip.d.ts.map +1 -0
  49. package/build/isClip/isClip.ios.d.ts +4 -0
  50. package/build/isClip/isClip.ios.d.ts.map +1 -0
  51. package/build/isClip/isClip.ios.js +9 -0
  52. package/build/isClip/isClip.ios.js.map +1 -0
  53. package/build/isClip/isClip.js +5 -0
  54. package/build/isClip/isClip.js.map +1 -0
  55. package/build/isClip/types.d.ts +2 -0
  56. package/build/isClip/types.d.ts.map +1 -0
  57. package/build/isClip/types.js +2 -0
  58. package/build/isClip/types.js.map +1 -0
  59. package/expo-module.config.json +6 -0
  60. package/ios/ReactNativeAppClip.podspec +27 -0
  61. package/ios/ReactNativeAppClipModule.swift +82 -0
  62. package/ios/reactnativeappclip.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  63. package/ios/reactnativeappclip.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  64. package/package.json +53 -0
  65. package/plugin/build/cliPlugin.d.ts +3 -0
  66. package/plugin/build/cliPlugin.js +26 -0
  67. package/plugin/build/index.d.ts +17 -0
  68. package/plugin/build/index.js +63 -0
  69. package/plugin/build/lib/getAppClipEntitlements.d.ts +8 -0
  70. package/plugin/build/lib/getAppClipEntitlements.js +39 -0
  71. package/plugin/build/withCompression.d.ts +5 -0
  72. package/plugin/build/withCompression.js +100 -0
  73. package/plugin/build/withConfig.d.ts +8 -0
  74. package/plugin/build/withConfig.js +66 -0
  75. package/plugin/build/withEntitlements.d.ts +8 -0
  76. package/plugin/build/withEntitlements.js +30 -0
  77. package/plugin/build/withPlist.d.ts +7 -0
  78. package/plugin/build/withPlist.js +73 -0
  79. package/plugin/build/withPodfile.d.ts +5 -0
  80. package/plugin/build/withPodfile.js +82 -0
  81. package/plugin/build/withXcode.d.ts +8 -0
  82. package/plugin/build/withXcode.js +51 -0
  83. package/plugin/build/xcode/addBuildPhases.d.ts +12 -0
  84. package/plugin/build/xcode/addBuildPhases.js +44 -0
  85. package/plugin/build/xcode/addPbxGroup.d.ts +6 -0
  86. package/plugin/build/xcode/addPbxGroup.js +69 -0
  87. package/plugin/build/xcode/addProductFile.d.ts +5 -0
  88. package/plugin/build/xcode/addProductFile.js +21 -0
  89. package/plugin/build/xcode/addTargetDependency.d.ts +4 -0
  90. package/plugin/build/xcode/addTargetDependency.js +14 -0
  91. package/plugin/build/xcode/addToPbxNativeTargetSection.d.ts +24 -0
  92. package/plugin/build/xcode/addToPbxNativeTargetSection.js +21 -0
  93. package/plugin/build/xcode/addToPbxProjectSection.d.ts +4 -0
  94. package/plugin/build/xcode/addToPbxProjectSection.js +14 -0
  95. package/plugin/build/xcode/addXCConfigurationList.d.ts +8 -0
  96. package/plugin/build/xcode/addXCConfigurationList.js +38 -0
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>IDEDidComputeMac32BitWarning</key>
6
+ <true/>
7
+ </dict>
8
+ </plist>
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@trentrand/react-native-app-clip",
3
+ "version": "0.6.2-beta.0",
4
+ "description": "Config plugin to add an App Clip to a React Native iOS app",
5
+ "main": "build/index.js",
6
+ "types": "build/index.d.ts",
7
+ "files": [
8
+ "ios",
9
+ "plugin/build",
10
+ "build",
11
+ "README.md",
12
+ "expo-module.config.json",
13
+ "app.plugin.js"
14
+ ],
15
+ "scripts": {
16
+ "build": "expo-module build",
17
+ "build:plugin": "expo-module build plugin",
18
+ "clean": "expo-module clean",
19
+ "lint": "expo-module lint",
20
+ "test": "expo-module test",
21
+ "prepare": "expo-module prepare",
22
+ "prepublishOnly": "expo-module prepublishOnly",
23
+ "expo-module": "expo-module",
24
+ "open:ios": "xed example/ios",
25
+ "open:android": "open -a \"Android Studio\" example/android"
26
+ },
27
+ "keywords": [
28
+ "react-native",
29
+ "expo",
30
+ "react-native-app-clip",
31
+ "ReactNativeAppClip"
32
+ ],
33
+ "repository": "https://github.com/bndkt/react-native-app-clip",
34
+ "bugs": {
35
+ "url": "https://github.com/bndkt/react-native-app-clip/issues"
36
+ },
37
+ "author": "Benedikt Müller <91166910+bndkt@users.noreply.github.com> (https://github.com/bndkt)",
38
+ "license": "MIT",
39
+ "homepage": "https://github.com/bndkt/react-native-app-clip#readme",
40
+ "dependencies": {
41
+ "@expo/config-plugins": "~10.0.0",
42
+ "@expo/plist": "~0.3.0"
43
+ },
44
+ "devDependencies": {
45
+ "expo-module-scripts": "^4.0.0",
46
+ "expo-modules-core": "~2.3.0"
47
+ },
48
+ "peerDependencies": {
49
+ "expo": "*",
50
+ "react": "*",
51
+ "react-native": "*"
52
+ }
53
+ }
@@ -0,0 +1,3 @@
1
+ export declare const run: (config: {
2
+ dependencies: Record<string, object>;
3
+ }, exclude: string[]) => Promise<void>;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.run = void 0;
4
+ const run = async (config, exclude) => {
5
+ // Validation
6
+ if (typeof config !== "object") {
7
+ throw new Error("config must be an object");
8
+ }
9
+ if (!config.dependencies) {
10
+ throw new Error("config must have a dependencies key");
11
+ }
12
+ if (!Array.isArray(exclude)) {
13
+ throw new Error("exclude must be an array");
14
+ }
15
+ for (const packageName of exclude) {
16
+ if (typeof packageName !== "string") {
17
+ throw new Error("exclude must be an array of strings");
18
+ }
19
+ }
20
+ // Removing excluded packages
21
+ for (const packageName of exclude) {
22
+ delete config.dependencies[packageName];
23
+ }
24
+ console.log(JSON.stringify(config));
25
+ };
26
+ exports.run = run;
@@ -0,0 +1,17 @@
1
+ import { type ConfigPlugin } from "expo/config-plugins";
2
+ declare const withAppClip: ConfigPlugin<{
3
+ name?: string;
4
+ enabled?: boolean;
5
+ bundleIdSuffix?: string;
6
+ targetSuffix?: string;
7
+ groupIdentifier?: string;
8
+ deploymentTarget?: string;
9
+ requestEphemeralUserNotification?: boolean;
10
+ requestLocationConfirmation?: boolean;
11
+ appleSignin?: boolean;
12
+ applePayMerchantIds?: string[];
13
+ excludedPackages?: string[];
14
+ pushNotifications?: boolean;
15
+ enableCompression?: boolean;
16
+ }>;
17
+ export default withAppClip;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const config_plugins_1 = require("expo/config-plugins");
4
+ const withConfig_1 = require("./withConfig");
5
+ const withCompression_1 = require("./withCompression");
6
+ const withEntitlements_1 = require("./withEntitlements");
7
+ const withPlist_1 = require("./withPlist");
8
+ const withPodfile_1 = require("./withPodfile");
9
+ const withXcode_1 = require("./withXcode");
10
+ const DeviceFamily_1 = require("@expo/config-plugins/build/ios/DeviceFamily");
11
+ const withAppClip = (config, { name, enabled, bundleIdSuffix, targetSuffix, groupIdentifier, deploymentTarget, requestEphemeralUserNotification, requestLocationConfirmation, appleSignin, applePayMerchantIds, excludedPackages, pushNotifications, enableCompression, } = {}) => {
12
+ name ??= "Clip";
13
+ bundleIdSuffix ??= "Clip";
14
+ targetSuffix ??= "Clip";
15
+ deploymentTarget ??= "15.1";
16
+ requestEphemeralUserNotification ??= false;
17
+ requestLocationConfirmation ??= false;
18
+ appleSignin ??= false;
19
+ enabled ??= true;
20
+ pushNotifications ??= false;
21
+ if (!enabled) {
22
+ return config;
23
+ }
24
+ if (!config.ios?.bundleIdentifier) {
25
+ throw new Error("No bundle identifier specified in app config");
26
+ }
27
+ const bundleIdentifier = `${config.ios.bundleIdentifier}.${bundleIdSuffix}`;
28
+ const targetName = `${config_plugins_1.IOSConfig.XcodeUtils.sanitizedName(config.name)}${targetSuffix}`;
29
+ const modifiedConfig = (0, config_plugins_1.withPlugins)(config, [
30
+ DeviceFamily_1.withDeviceFamily,
31
+ [
32
+ withConfig_1.withConfig,
33
+ { targetName, bundleIdentifier, appleSignin, applePayMerchantIds, pushNotifications },
34
+ ],
35
+ [
36
+ withEntitlements_1.withEntitlements,
37
+ { targetName, groupIdentifier, appleSignin, applePayMerchantIds, pushNotifications },
38
+ ],
39
+ [withPodfile_1.withPodfile, { targetName, excludedPackages }],
40
+ [
41
+ withPlist_1.withPlist,
42
+ {
43
+ targetName,
44
+ deploymentTarget,
45
+ requestEphemeralUserNotification,
46
+ requestLocationConfirmation,
47
+ },
48
+ ],
49
+ [
50
+ withXcode_1.withXcode,
51
+ {
52
+ name,
53
+ targetName,
54
+ bundleIdentifier,
55
+ deploymentTarget,
56
+ enableCompression,
57
+ },
58
+ ],
59
+ [withCompression_1.withCompression, { targetName, enableCompression }],
60
+ ]);
61
+ return modifiedConfig;
62
+ };
63
+ exports.default = withAppClip;
@@ -0,0 +1,8 @@
1
+ import type { ExportedConfigWithProps, InfoPlist } from "expo/config-plugins";
2
+ export declare function getAppClipEntitlements(iosConfig: ExportedConfigWithProps["ios"], { groupIdentifier, appleSignin, applePayMerchantIds, pushNotifications, }: {
3
+ groupIdentifier?: string;
4
+ appleSignin: boolean;
5
+ applePayMerchantIds?: string[];
6
+ pushNotifications: boolean;
7
+ }): InfoPlist;
8
+ export declare function addApplicationGroupsEntitlement(entitlements: InfoPlist, groupIdentifier?: string): InfoPlist;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAppClipEntitlements = getAppClipEntitlements;
4
+ exports.addApplicationGroupsEntitlement = addApplicationGroupsEntitlement;
5
+ function getAppClipEntitlements(iosConfig, { groupIdentifier, appleSignin, applePayMerchantIds, pushNotifications, }) {
6
+ const appBundleIdentifier = iosConfig?.bundleIdentifier;
7
+ const entitlements = {
8
+ "com.apple.developer.parent-application-identifiers": [
9
+ `$(AppIdentifierPrefix)${appBundleIdentifier}`,
10
+ ],
11
+ "com.apple.developer.on-demand-install-capable": true,
12
+ };
13
+ addApplicationGroupsEntitlement(entitlements, groupIdentifier);
14
+ if (appleSignin) {
15
+ entitlements["com.apple.developer.applesignin"] = ["Default"];
16
+ }
17
+ if (applePayMerchantIds) {
18
+ entitlements["com.apple.developer.in-app-payments"] = applePayMerchantIds;
19
+ }
20
+ if (pushNotifications) {
21
+ // XCode automatically changes this to "production" when archiving https://stackoverflow.com/a/42293632/4047926
22
+ entitlements["aps-environment"] = "development";
23
+ }
24
+ if (iosConfig?.associatedDomains) {
25
+ entitlements["com.apple.developer.associated-domains"] =
26
+ iosConfig.associatedDomains;
27
+ }
28
+ return entitlements;
29
+ }
30
+ function addApplicationGroupsEntitlement(entitlements, groupIdentifier) {
31
+ if (groupIdentifier) {
32
+ const existingApplicationGroups = entitlements["com.apple.security.application-groups"] ?? [];
33
+ entitlements["com.apple.security.application-groups"] = [
34
+ groupIdentifier,
35
+ ...existingApplicationGroups,
36
+ ];
37
+ }
38
+ return entitlements;
39
+ }
@@ -0,0 +1,5 @@
1
+ import { type ConfigPlugin } from "expo/config-plugins";
2
+ export declare const withCompression: ConfigPlugin<{
3
+ targetName: string;
4
+ enableCompression?: boolean;
5
+ }>;
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.withCompression = void 0;
7
+ const config_plugins_1 = require("expo/config-plugins");
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const withCompression = (config, { targetName, enableCompression = false }) => {
11
+ if (!enableCompression) {
12
+ return config;
13
+ }
14
+ // Use withDangerousMod but ensure it runs AFTER all other mods
15
+ // by adding it at priority 0 (runs last)
16
+ return (0, config_plugins_1.withDangerousMod)(config, [
17
+ "ios",
18
+ async (config) => {
19
+ const projectRoot = config.modRequest.platformProjectRoot;
20
+ console.log("🔧 Configuring App Clip compression...");
21
+ // Modify AppDelegate to handle decompression
22
+ const appDelegatePath = path_1.default.join(projectRoot, targetName, "AppDelegate.swift");
23
+ if (fs_1.default.existsSync(appDelegatePath)) {
24
+ modifyAppDelegate(appDelegatePath);
25
+ }
26
+ else {
27
+ console.warn(`⚠️ AppDelegate not found at ${appDelegatePath}`);
28
+ }
29
+ return config;
30
+ },
31
+ ]);
32
+ };
33
+ exports.withCompression = withCompression;
34
+ function modifyAppDelegate(appDelegatePath) {
35
+ let content = fs_1.default.readFileSync(appDelegatePath, "utf8");
36
+ // Check if already modified
37
+ if (content.includes("decompressZlibBundle")) {
38
+ console.log("✅ AppDelegate already configured for compression");
39
+ return;
40
+ }
41
+ // Add Compression import
42
+ if (!content.includes("import Compression")) {
43
+ content = content.replace(/(import.*\n)+/, (imports) => imports + "import Compression\n");
44
+ }
45
+ // Find and replace the bundleURL() function
46
+ const bundleURLPattern = /override func bundleURL\(\) -> URL\? \{[\s\S]*?#if DEBUG[\s\S]*?#else[\s\S]*?#endif[\s\S]*?\}/;
47
+ if (bundleURLPattern.test(content)) {
48
+ content = content.replace(bundleURLPattern, `override func bundleURL() -> URL? {
49
+ #if DEBUG
50
+ return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: ".expo/.virtual-metro-entry")
51
+ #else
52
+ return decompressedBundleURL()
53
+ #endif
54
+ }
55
+
56
+ // MARK: - Bundle Decompression
57
+
58
+ private func decompressedBundleURL() -> URL? {
59
+ // Try compressed bundle first
60
+ if let zlibPath = Bundle.main.url(forResource: "main.jsbundle", withExtension: "zlib") {
61
+ return decompressZlibBundle(at: zlibPath)
62
+ }
63
+ // Fallback to uncompressed
64
+ return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
65
+ }
66
+
67
+ private func decompressZlibBundle(at compressedURL: URL) -> URL? {
68
+ let decompressedPath = NSTemporaryDirectory() + "main.jsbundle"
69
+ let decompressedURL = URL(fileURLWithPath: decompressedPath)
70
+
71
+ // ALWAYS remove existing temp file to ensure we don't load stale code after an update
72
+ try? FileManager.default.removeItem(at: decompressedURL)
73
+
74
+ do {
75
+ let compressedData = try Data(contentsOf: compressedURL)
76
+
77
+ // Decompress using NSData decompression (available iOS 13+)
78
+ guard let decompressedData = try? (compressedData as NSData).decompressed(using: .zlib) as Data else {
79
+ print("❌ Failed to decompress bundle")
80
+ return nil
81
+ }
82
+
83
+ // Use atomic write to ensure integrity
84
+ try decompressedData.write(to: decompressedURL, options: .atomic)
85
+
86
+ print("✅ Bundle decompressed: \\(compressedData.count / 1024) KB → \\(decompressedData.count / 1024) KB")
87
+
88
+ return decompressedURL
89
+ } catch {
90
+ print("❌ Decompression error: \\(error)")
91
+ return nil
92
+ }
93
+ }`);
94
+ fs_1.default.writeFileSync(appDelegatePath, content);
95
+ console.log("✅ Modified AppDelegate for decompression");
96
+ }
97
+ else {
98
+ console.warn("⚠️ Could not find bundleURL() function in AppDelegate");
99
+ }
100
+ }
@@ -0,0 +1,8 @@
1
+ import type { ConfigPlugin } from "expo/config-plugins";
2
+ export declare const withConfig: ConfigPlugin<{
3
+ targetName: string;
4
+ bundleIdentifier: string;
5
+ appleSignin: boolean;
6
+ applePayMerchantIds: string[];
7
+ pushNotifications: boolean;
8
+ }>;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.withConfig = void 0;
4
+ const getAppClipEntitlements_1 = require("./lib/getAppClipEntitlements");
5
+ const withConfig = (config, { targetName, bundleIdentifier, appleSignin, applePayMerchantIds, pushNotifications }) => {
6
+ let configIndex = null;
7
+ config.extra?.eas?.build?.experimental?.ios?.appExtensions?.forEach((ext, index) => {
8
+ if (ext.targetName === targetName) {
9
+ configIndex = index;
10
+ }
11
+ });
12
+ if (!configIndex) {
13
+ config.extra = {
14
+ ...config.extra,
15
+ eas: {
16
+ ...config.extra?.eas,
17
+ build: {
18
+ ...config.extra?.eas?.build,
19
+ experimental: {
20
+ ...config.extra?.eas?.build?.experimental,
21
+ ios: {
22
+ ...config.extra?.eas?.build?.experimental?.ios,
23
+ appExtensions: [
24
+ ...(config.extra?.eas?.build?.experimental?.ios
25
+ ?.appExtensions ?? []),
26
+ {
27
+ targetName,
28
+ bundleIdentifier,
29
+ },
30
+ ],
31
+ },
32
+ },
33
+ },
34
+ },
35
+ };
36
+ configIndex = 0;
37
+ }
38
+ if (configIndex !== null && config.extra) {
39
+ const appClipConfig = config.extra.eas.build.experimental.ios.appExtensions[configIndex];
40
+ appClipConfig.entitlements = {
41
+ ...appClipConfig.entitlements,
42
+ ...(0, getAppClipEntitlements_1.getAppClipEntitlements)(config.ios, {
43
+ appleSignin,
44
+ applePayMerchantIds,
45
+ // groupIdentifier, // Throws an error in EAS
46
+ pushNotifications,
47
+ }),
48
+ };
49
+ }
50
+ // Entitlements
51
+ config.ios = {
52
+ ...config.ios,
53
+ entitlements: {
54
+ // ...addApplicationGroupsEntitlement(
55
+ // config.ios?.entitlements ?? {},
56
+ // groupIdentifier,
57
+ // ),
58
+ ...config.ios?.entitlements,
59
+ "com.apple.developer.associated-appclip-app-identifiers": [
60
+ `$(AppIdentifierPrefix)${bundleIdentifier}`,
61
+ ],
62
+ },
63
+ };
64
+ return config;
65
+ };
66
+ exports.withConfig = withConfig;
@@ -0,0 +1,8 @@
1
+ import { type ConfigPlugin } from "expo/config-plugins";
2
+ export declare const withEntitlements: ConfigPlugin<{
3
+ targetName: string;
4
+ groupIdentifier: string;
5
+ appleSignin: boolean;
6
+ applePayMerchantIds: string[];
7
+ pushNotifications: boolean;
8
+ }>;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.withEntitlements = void 0;
7
+ const plist_1 = __importDefault(require("@expo/plist"));
8
+ const config_plugins_1 = require("expo/config-plugins");
9
+ const node_fs_1 = __importDefault(require("node:fs"));
10
+ const node_path_1 = __importDefault(require("node:path"));
11
+ const getAppClipEntitlements_1 = require("./lib/getAppClipEntitlements");
12
+ const withEntitlements = (config, { targetName, groupIdentifier, appleSignin, applePayMerchantIds, pushNotifications }) => {
13
+ return (0, config_plugins_1.withInfoPlist)(config, (config) => {
14
+ const targetPath = node_path_1.default.join(config.modRequest.platformProjectRoot, targetName);
15
+ const filePath = node_path_1.default.join(targetPath, `${targetName}.entitlements`);
16
+ if (config.ios === undefined) {
17
+ throw new Error("Missing iOS config");
18
+ }
19
+ const appClipEntitlements = (0, getAppClipEntitlements_1.getAppClipEntitlements)(config.ios, {
20
+ groupIdentifier,
21
+ appleSignin,
22
+ applePayMerchantIds,
23
+ pushNotifications,
24
+ });
25
+ node_fs_1.default.mkdirSync(node_path_1.default.dirname(filePath), { recursive: true });
26
+ node_fs_1.default.writeFileSync(filePath, plist_1.default.build(appClipEntitlements));
27
+ return config;
28
+ });
29
+ };
30
+ exports.withEntitlements = withEntitlements;
@@ -0,0 +1,7 @@
1
+ import { type ConfigPlugin } from "expo/config-plugins";
2
+ export declare const withPlist: ConfigPlugin<{
3
+ targetName: string;
4
+ deploymentTarget: string;
5
+ requestEphemeralUserNotification: boolean;
6
+ requestLocationConfirmation: boolean;
7
+ }>;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.withPlist = void 0;
7
+ const plist_1 = __importDefault(require("@expo/plist"));
8
+ const config_plugins_1 = require("expo/config-plugins");
9
+ const node_fs_1 = __importDefault(require("node:fs"));
10
+ const node_path_1 = __importDefault(require("node:path"));
11
+ /**
12
+ * List of keys that are not allowed in the Info.plist due to not being supported in App Clip. Add to this array as new build issues arise.
13
+ */
14
+ const DisallowedPlistKeys = [
15
+ "UIBackgroundModes",
16
+ ];
17
+ const withPlist = (config, { targetName, deploymentTarget, requestEphemeralUserNotification, requestLocationConfirmation, }) => {
18
+ return (0, config_plugins_1.withInfoPlist)(config, (config) => {
19
+ const targetPath = node_path_1.default.join(config.modRequest.platformProjectRoot, targetName);
20
+ // Info.plist
21
+ const filePath = node_path_1.default.join(targetPath, "Info.plist");
22
+ const infoPlist = {
23
+ NSAppClip: {
24
+ NSAppClipRequestEphemeralUserNotification: requestEphemeralUserNotification,
25
+ NSAppClipRequestLocationConfirmation: requestLocationConfirmation,
26
+ },
27
+ NSAppTransportSecurity: {
28
+ NSAllowsArbitraryLoads: config.developmentClient,
29
+ NSExceptionDomains: {
30
+ localhost: {
31
+ NSExceptionAllowsInsecureHTTPLoads: config.developmentClient,
32
+ },
33
+ },
34
+ NSAllowsLocalNetworking: config.developmentClient,
35
+ },
36
+ CFBundleName: "$(PRODUCT_NAME)",
37
+ CFBundleDisplayName: "$(PRODUCT_NAME)",
38
+ CFBundleIdentifier: "$(PRODUCT_BUNDLE_IDENTIFIER)",
39
+ CFBundleVersion: "$(CURRENT_PROJECT_VERSION)",
40
+ CFBundleExecutable: "$(EXECUTABLE_NAME)",
41
+ CFBundlePackageType: "$(PRODUCT_BUNDLE_PACKAGE_TYPE)",
42
+ CFBundleShortVersionString: config.version,
43
+ UIViewControllerBasedStatusBarAppearance: "NO",
44
+ UILaunchStoryboardName: "SplashScreen",
45
+ UIRequiresFullScreen: true,
46
+ MinimumOSVersion: deploymentTarget,
47
+ };
48
+ if (config.ios?.infoPlist) {
49
+ for (const key of Object.keys(config.ios?.infoPlist)) {
50
+ if (config.ios?.infoPlist && !DisallowedPlistKeys.some((disallowedKey) => disallowedKey === key)) {
51
+ infoPlist[key] = config.ios.infoPlist[key];
52
+ }
53
+ }
54
+ }
55
+ node_fs_1.default.mkdirSync(node_path_1.default.dirname(filePath), {
56
+ recursive: true,
57
+ });
58
+ node_fs_1.default.writeFileSync(filePath, plist_1.default.build(infoPlist));
59
+ // Expo.plist
60
+ const expoPlistFilePath = node_path_1.default.join(targetPath, "Supporting/Expo.plist");
61
+ const expoPlist = {
62
+ EXUpdatesRuntimeVersion: "exposdk:51.0.0", // TODO
63
+ // EXUpdatesURL: "", // TODO
64
+ EXUpdatesEnabled: false,
65
+ };
66
+ node_fs_1.default.mkdirSync(node_path_1.default.dirname(expoPlistFilePath), {
67
+ recursive: true,
68
+ });
69
+ node_fs_1.default.writeFileSync(expoPlistFilePath, plist_1.default.build(expoPlist));
70
+ return config;
71
+ });
72
+ };
73
+ exports.withPlist = withPlist;
@@ -0,0 +1,5 @@
1
+ import { type ConfigPlugin } from "expo/config-plugins";
2
+ export declare const withPodfile: ConfigPlugin<{
3
+ targetName: string;
4
+ excludedPackages?: string[];
5
+ }>;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.withPodfile = void 0;
7
+ const generateCode_1 = require("@expo/config-plugins/build/utils/generateCode");
8
+ const config_plugins_1 = require("expo/config-plugins");
9
+ const node_fs_1 = __importDefault(require("node:fs"));
10
+ const node_path_1 = __importDefault(require("node:path"));
11
+ const withPodfile = (config, { targetName, excludedPackages }) => {
12
+ // return config;
13
+ return (0, config_plugins_1.withDangerousMod)(config, [
14
+ "ios",
15
+ (config) => {
16
+ const podFilePath = node_path_1.default.join(config.modRequest.platformProjectRoot, "Podfile");
17
+ let podfileContent = node_fs_1.default.readFileSync(podFilePath).toString();
18
+ const useExpoModules = excludedPackages && excludedPackages.length > 0
19
+ ? `exclude = ["${excludedPackages.join(`", "`)}"]\n use_expo_modules!(exclude: exclude)`
20
+ : "use_expo_modules!";
21
+ const appClipTarget = `
22
+ target '${targetName}' do
23
+ ${useExpoModules}
24
+
25
+ if ENV['EXPO_USE_COMMUNITY_AUTOLINKING'] == '1'
26
+ config_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"];
27
+ else
28
+ config_command = [
29
+ 'npx',
30
+ 'expo-modules-autolinking',
31
+ 'react-native-config',
32
+ '--json',
33
+ '--platform',
34
+ 'ios'
35
+ ]
36
+ end
37
+
38
+ # Running the command in the same manner as \`use_react_native\` then running that result through our cliPlugin
39
+ json, message, status = Pod::Executable.capture_command(config_command[0], config_command[1..], capture: :both)
40
+ if not status.success?
41
+ Pod::UI.warn "The command: '#{config_command.join(" ").bold.yellow}' returned a status code of #{status.exitstatus.to_s.bold.red}, #{message}", [
42
+ "App Clip autolinking failed. Please ensure autolinking works correctly for the main app target and try again.",
43
+ ]
44
+ exit(status.exitstatus)
45
+ end
46
+
47
+ # \`react-native-app-clip\` resolves to react-native-app-clip/build/index.js
48
+ clip_command = [
49
+ 'node',
50
+ '--no-warnings',
51
+ '--eval',
52
+ 'require(require.resolve(\\'react-native-app-clip\\')+\\'/../../plugin/build/cliPlugin.js\\').run(' + json + ', [${(excludedPackages ?? []).map((packageName) => `"${packageName}"`).join(", ")}])'
53
+ ]
54
+
55
+ config = use_native_modules!(clip_command)
56
+
57
+ use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
58
+ use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']
59
+
60
+ use_react_native!(
61
+ :path => config[:reactNativePath],
62
+ :hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes',
63
+ # An absolute path to your application root.
64
+ :app_path => "#{Pod::Config.instance.installation_root}/..",
65
+ :privacy_file_aggregation_enabled => podfile_properties['apple.privacyManifestAggregationEnabled'] != 'false',
66
+ )
67
+ end
68
+ `;
69
+ podfileContent = (0, generateCode_1.mergeContents)({
70
+ tag: "Generated by react-native-app-clip",
71
+ src: podfileContent,
72
+ newSrc: appClipTarget,
73
+ anchor: "use_expo_modules!",
74
+ offset: 0,
75
+ comment: "#",
76
+ }).contents;
77
+ node_fs_1.default.writeFileSync(podFilePath, podfileContent);
78
+ return config;
79
+ },
80
+ ]);
81
+ };
82
+ exports.withPodfile = withPodfile;
@@ -0,0 +1,8 @@
1
+ import { type ConfigPlugin } from "expo/config-plugins";
2
+ export declare const withXcode: ConfigPlugin<{
3
+ name: string;
4
+ targetName: string;
5
+ bundleIdentifier: string;
6
+ deploymentTarget: string;
7
+ enableCompression?: boolean;
8
+ }>;