sitepong 0.2.2 → 0.2.4
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/android/build.gradle +39 -0
- package/android/src/main/java/com/sitepong/deviceid/DeviceIdHelper.kt +45 -0
- package/android/src/main/java/com/sitepong/deviceid/DeviceIdModule.kt +45 -0
- package/android/src/main/java/com/sitepong/screenrecorder/ChunkUploader.kt +78 -0
- package/android/src/main/java/com/sitepong/screenrecorder/H264Encoder.kt +163 -0
- package/android/src/main/java/com/sitepong/screenrecorder/ScreenCapture.kt +103 -0
- package/android/src/main/java/com/sitepong/screenrecorder/ScreenRecorderModule.kt +80 -0
- package/android/src/main/java/com/sitepong/screenrecorder/SensitiveViewManager.kt +19 -0
- package/app.plugin.js +426 -0
- package/dist/cdn/sitepong.min.js +5 -5
- package/dist/cdn/sitepong.min.js.map +1 -1
- package/dist/entries/rn.d.ts +188 -16
- package/dist/entries/rn.js +188 -35
- package/dist/entries/rn.js.map +1 -1
- package/dist/entries/web.js +2 -1
- package/dist/entries/web.js.map +1 -1
- package/dist/entries/web.mjs +2 -1
- package/dist/entries/web.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -1
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.js +2 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +2 -1
- package/dist/react/index.mjs.map +1 -1
- package/expo-module.config.json +16 -0
- package/ios/DeviceId/DeviceIdModule.swift +55 -0
- package/ios/DeviceId/KeychainHelper.swift +68 -0
- package/ios/LiveActivity/ConfigStore.swift +43 -0
- package/ios/LiveActivity/DSLNode.swift +188 -0
- package/ios/LiveActivity/SitePongActivityAttributes.swift +112 -0
- package/ios/LiveActivity/SitePongLiveActivityModule.swift +250 -0
- package/ios/LiveActivity/widget/ColorHex.swift +30 -0
- package/ios/LiveActivity/widget/DSLAnimations.swift +128 -0
- package/ios/LiveActivity/widget/DSLRenderer.swift +538 -0
- package/ios/LiveActivity/widget/SitePongLiveActivityWidget.swift +393 -0
- package/ios/LiveActivity/widget/SitePongWidgetBundle.swift +84 -0
- package/ios/ScreenRecorder/ChunkUploader.swift +52 -0
- package/ios/ScreenRecorder/H264Encoder.swift +229 -0
- package/ios/ScreenRecorder/ScreenCapture.swift +149 -0
- package/ios/ScreenRecorder/ScreenRecorderModule.swift +179 -0
- package/ios/ScreenRecorder/SensitiveViewManager.swift +63 -0
- package/ios/Sitepong.podspec +57 -0
- package/ios/WatchtowerCore/Screenshotter.swift +163 -0
- package/ios/WatchtowerCore/SwiftUIModifiers.swift +78 -0
- package/ios/WatchtowerCore/Swizzling.swift +59 -0
- package/ios/WatchtowerCore/TapEvent.swift +61 -0
- package/ios/WatchtowerCore/Transport.swift +136 -0
- package/ios/WatchtowerCore/UIViewExtensions.swift +31 -0
- package/ios/WatchtowerCore/Watchtower.swift +80 -0
- package/ios/WatchtowerCore/WatchtowerEngine.swift +565 -0
- package/ios/WatchtowerCore/WatchtowerHash.swift +120 -0
- package/ios/WatchtowerCore/WatchtowerRegistry.swift +87 -0
- package/package.json +19 -8
package/app.plugin.js
ADDED
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SitePong SDK — Expo config plugin (the ONE plugin).
|
|
3
|
+
*
|
|
4
|
+
* `sitepong` is a single package that ships all native capabilities. Its config
|
|
5
|
+
* plugin therefore does what the old per-feature plugins used to do:
|
|
6
|
+
*
|
|
7
|
+
* 1. Screen recording / Watchtower tap capture — NO native config needed.
|
|
8
|
+
* (View-hierarchy capture; no screen-record entitlement, no purpose string.)
|
|
9
|
+
* The Watchtower engine is compiled into the Sitepong pod, so there is no
|
|
10
|
+
* Podfile patch anymore — that whole fragility is gone.
|
|
11
|
+
* 2. Device ID — writes PrivacyInfo.xcprivacy declaring Keychain-backed device
|
|
12
|
+
* id usage for analytics (Apple requirement since May 2024). Always applied.
|
|
13
|
+
* 3. Live Activities — a WidgetKit app-extension target. This is the ONLY piece
|
|
14
|
+
* that alters the Xcode project, so it is OPT-IN: enable with
|
|
15
|
+
* ["sitepong", { "liveActivities": true }]
|
|
16
|
+
* (optionally { "appGroupId": "group.com.myapp" }). A plain ["sitepong"]
|
|
17
|
+
* links capture + device id and leaves the Xcode project otherwise untouched.
|
|
18
|
+
*
|
|
19
|
+
* Usage:
|
|
20
|
+
* ["sitepong"] // capture + device id
|
|
21
|
+
* ["sitepong", { "liveActivities": true }] // + Live Activities
|
|
22
|
+
* ["sitepong", { "liveActivities": true, "appGroupId": "group.com.myapp" }]
|
|
23
|
+
*/
|
|
24
|
+
const fs = require('fs');
|
|
25
|
+
const path = require('path');
|
|
26
|
+
|
|
27
|
+
// Resolve Expo's config-plugins from the CONSUMING app (this package is often
|
|
28
|
+
// symlinked and has no expo of its own). expo prebuild runs in the app context.
|
|
29
|
+
function resolveConfigPlugins() {
|
|
30
|
+
const candidates = ['@expo/config-plugins', 'expo/config-plugins'];
|
|
31
|
+
const searchPaths = [
|
|
32
|
+
process.cwd(),
|
|
33
|
+
path.join(process.cwd(), 'node_modules'),
|
|
34
|
+
__dirname,
|
|
35
|
+
];
|
|
36
|
+
for (const name of candidates) {
|
|
37
|
+
try {
|
|
38
|
+
return require(require.resolve(name, { paths: searchPaths }));
|
|
39
|
+
} catch (_) {
|
|
40
|
+
/* try next */
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return require('@expo/config-plugins');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const {
|
|
47
|
+
withXcodeProject,
|
|
48
|
+
withInfoPlist,
|
|
49
|
+
withEntitlementsPlist,
|
|
50
|
+
} = resolveConfigPlugins();
|
|
51
|
+
|
|
52
|
+
// ─── Device ID: PrivacyInfo.xcprivacy ────────────────────────────────────────
|
|
53
|
+
|
|
54
|
+
const PRIVACY_INFO = `<?xml version="1.0" encoding="UTF-8"?>
|
|
55
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
56
|
+
<plist version="1.0">
|
|
57
|
+
<dict>
|
|
58
|
+
<key>NSPrivacyTracking</key>
|
|
59
|
+
<false/>
|
|
60
|
+
<key>NSPrivacyCollectedDataTypes</key>
|
|
61
|
+
<array>
|
|
62
|
+
<dict>
|
|
63
|
+
<key>NSPrivacyCollectedDataType</key>
|
|
64
|
+
<string>NSPrivacyCollectedDataTypeDeviceID</string>
|
|
65
|
+
<key>NSPrivacyCollectedDataTypeLinked</key>
|
|
66
|
+
<false/>
|
|
67
|
+
<key>NSPrivacyCollectedDataTypeTracking</key>
|
|
68
|
+
<false/>
|
|
69
|
+
<key>NSPrivacyCollectedDataTypePurposes</key>
|
|
70
|
+
<array>
|
|
71
|
+
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
|
|
72
|
+
</array>
|
|
73
|
+
</dict>
|
|
74
|
+
</array>
|
|
75
|
+
<key>NSPrivacyAccessedAPITypes</key>
|
|
76
|
+
<array>
|
|
77
|
+
<dict>
|
|
78
|
+
<key>NSPrivacyAccessedAPIType</key>
|
|
79
|
+
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
|
|
80
|
+
<key>NSPrivacyAccessedAPITypeReasons</key>
|
|
81
|
+
<array>
|
|
82
|
+
<string>CA92.1</string>
|
|
83
|
+
</array>
|
|
84
|
+
</dict>
|
|
85
|
+
</array>
|
|
86
|
+
</dict>
|
|
87
|
+
</plist>`;
|
|
88
|
+
|
|
89
|
+
function withDeviceIdPrivacy(config) {
|
|
90
|
+
return withXcodeProject(config, async (cfg) => {
|
|
91
|
+
const projectRoot = cfg.modRequest.projectRoot;
|
|
92
|
+
const iosDir = path.join(
|
|
93
|
+
projectRoot,
|
|
94
|
+
'ios',
|
|
95
|
+
cfg.modRequest.projectName || '',
|
|
96
|
+
);
|
|
97
|
+
const privacyPath = path.join(iosDir, 'PrivacyInfo.xcprivacy');
|
|
98
|
+
if (!fs.existsSync(privacyPath)) {
|
|
99
|
+
fs.mkdirSync(path.dirname(privacyPath), { recursive: true });
|
|
100
|
+
fs.writeFileSync(privacyPath, PRIVACY_INFO);
|
|
101
|
+
}
|
|
102
|
+
return cfg;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ─── Live Activities: WidgetKit app-extension target (opt-in) ────────────────
|
|
107
|
+
|
|
108
|
+
const EXTENSION_NAME = 'SitePongLiveActivityWidget';
|
|
109
|
+
|
|
110
|
+
// All Swift compiled into the Widget Extension target. These live under
|
|
111
|
+
// ios/LiveActivity/ in the sitepong package (they are excluded from the main
|
|
112
|
+
// pod by Sitepong.podspec). SitePongActivityAttributes is shared with the main
|
|
113
|
+
// app module and is also compiled into the pod — the extension needs its own
|
|
114
|
+
// copy because app extensions don't link the app's pods.
|
|
115
|
+
const WIDGET_SOURCE_FILES = [
|
|
116
|
+
{ src: 'ios/LiveActivity/SitePongActivityAttributes.swift', name: 'SitePongActivityAttributes.swift' },
|
|
117
|
+
{ src: 'ios/LiveActivity/widget/SitePongWidgetBundle.swift', name: 'SitePongWidgetBundle.swift' },
|
|
118
|
+
{ src: 'ios/LiveActivity/widget/SitePongLiveActivityWidget.swift', name: 'SitePongLiveActivityWidget.swift' },
|
|
119
|
+
{ src: 'ios/LiveActivity/widget/DSLRenderer.swift', name: 'DSLRenderer.swift' },
|
|
120
|
+
// DSLNode + ConfigStore are shared with the main app module (compiled into the
|
|
121
|
+
// Sitepong pod), so they live at ios/LiveActivity/ root, not under widget/.
|
|
122
|
+
{ src: 'ios/LiveActivity/DSLNode.swift', name: 'DSLNode.swift' },
|
|
123
|
+
{ src: 'ios/LiveActivity/widget/DSLAnimations.swift', name: 'DSLAnimations.swift' },
|
|
124
|
+
{ src: 'ios/LiveActivity/ConfigStore.swift', name: 'ConfigStore.swift' },
|
|
125
|
+
{ src: 'ios/LiveActivity/widget/ColorHex.swift', name: 'ColorHex.swift' },
|
|
126
|
+
];
|
|
127
|
+
|
|
128
|
+
const WIDGET_INFO_PLIST = `<?xml version="1.0" encoding="UTF-8"?>
|
|
129
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
130
|
+
<plist version="1.0">
|
|
131
|
+
<dict>
|
|
132
|
+
<key>NSExtension</key>
|
|
133
|
+
<dict>
|
|
134
|
+
<key>NSExtensionPointIdentifier</key>
|
|
135
|
+
<string>com.apple.widgetkit-extension</string>
|
|
136
|
+
</dict>
|
|
137
|
+
<key>CFBundleExecutable</key>
|
|
138
|
+
<string>$(EXECUTABLE_NAME)</string>
|
|
139
|
+
<key>CFBundleIdentifier</key>
|
|
140
|
+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
141
|
+
<key>CFBundleName</key>
|
|
142
|
+
<string>$(PRODUCT_NAME)</string>
|
|
143
|
+
<key>CFBundleDisplayName</key>
|
|
144
|
+
<string>${EXTENSION_NAME}</string>
|
|
145
|
+
<key>CFBundlePackageType</key>
|
|
146
|
+
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
|
147
|
+
<key>CFBundleShortVersionString</key>
|
|
148
|
+
<string>$(MARKETING_VERSION)</string>
|
|
149
|
+
<key>CFBundleVersion</key>
|
|
150
|
+
<string>$(CURRENT_PROJECT_VERSION)</string>
|
|
151
|
+
</dict>
|
|
152
|
+
</plist>`;
|
|
153
|
+
|
|
154
|
+
function generateEntitlementsPlist(entitlements) {
|
|
155
|
+
let entries = '';
|
|
156
|
+
for (const [key, value] of Object.entries(entitlements)) {
|
|
157
|
+
if (Array.isArray(value)) {
|
|
158
|
+
entries += ` <key>${key}</key>\n <array>\n`;
|
|
159
|
+
for (const item of value) entries += ` <string>${item}</string>\n`;
|
|
160
|
+
entries += ` </array>\n`;
|
|
161
|
+
} else if (typeof value === 'string') {
|
|
162
|
+
entries += ` <key>${key}</key>\n <string>${value}</string>\n`;
|
|
163
|
+
} else if (typeof value === 'boolean') {
|
|
164
|
+
entries += ` <key>${key}</key>\n <${value}/>\n`;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
168
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
169
|
+
<plist version="1.0">
|
|
170
|
+
<dict>
|
|
171
|
+
${entries}</dict>
|
|
172
|
+
</plist>`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function withLiveActivities(config, props) {
|
|
176
|
+
// 1. aps-environment entitlement on the main app (push tokens for updates).
|
|
177
|
+
config = withEntitlementsPlist(config, (cfg) => {
|
|
178
|
+
cfg.modResults['aps-environment'] =
|
|
179
|
+
cfg.modResults['aps-environment'] || 'development';
|
|
180
|
+
return cfg;
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// 2. Live Activities support in the main Info.plist.
|
|
184
|
+
config = withInfoPlist(config, (cfg) => {
|
|
185
|
+
cfg.modResults.NSSupportsLiveActivities = true;
|
|
186
|
+
cfg.modResults.NSSupportsLiveActivitiesFrequentUpdates = true;
|
|
187
|
+
return cfg;
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// 3. Add the Widget Extension target to the Xcode project.
|
|
191
|
+
config = withXcodeProject(config, async (cfg) => {
|
|
192
|
+
const xcodeProject = cfg.modResults;
|
|
193
|
+
const projectRoot = cfg.modRequest.projectRoot;
|
|
194
|
+
const bundleId = cfg.ios?.bundleIdentifier || 'com.app';
|
|
195
|
+
const extensionBundleId = `${bundleId}.${EXTENSION_NAME}`;
|
|
196
|
+
|
|
197
|
+
const extensionDir = path.join(projectRoot, 'ios', EXTENSION_NAME);
|
|
198
|
+
const packageRoot = __dirname;
|
|
199
|
+
|
|
200
|
+
if (!fs.existsSync(extensionDir)) {
|
|
201
|
+
fs.mkdirSync(extensionDir, { recursive: true });
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
for (const file of WIDGET_SOURCE_FILES) {
|
|
205
|
+
const srcPath = path.join(packageRoot, file.src);
|
|
206
|
+
const dstPath = path.join(extensionDir, file.name);
|
|
207
|
+
if (!fs.existsSync(srcPath)) {
|
|
208
|
+
console.warn(`[sitepong] Missing Live Activity source: ${srcPath}`);
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
fs.copyFileSync(srcPath, dstPath);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
fs.writeFileSync(path.join(extensionDir, 'Info.plist'), WIDGET_INFO_PLIST);
|
|
215
|
+
|
|
216
|
+
const entitlements = {};
|
|
217
|
+
if (props.appGroupId) {
|
|
218
|
+
entitlements['com.apple.security.application-groups'] = [props.appGroupId];
|
|
219
|
+
}
|
|
220
|
+
fs.writeFileSync(
|
|
221
|
+
path.join(extensionDir, `${EXTENSION_NAME}.entitlements`),
|
|
222
|
+
generateEntitlementsPlist(entitlements),
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
if (xcodeProject.pbxTargetByName(EXTENSION_NAME)) {
|
|
226
|
+
return cfg; // idempotent
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const target = xcodeProject.addTarget(
|
|
230
|
+
EXTENSION_NAME,
|
|
231
|
+
'app_extension',
|
|
232
|
+
EXTENSION_NAME,
|
|
233
|
+
extensionBundleId,
|
|
234
|
+
);
|
|
235
|
+
if (!target) {
|
|
236
|
+
console.warn('[sitepong] Failed to add Live Activity extension target');
|
|
237
|
+
return cfg;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const pbxFileRef = xcodeProject.hash.project.objects['PBXFileReference'];
|
|
241
|
+
const sourceFileRefs = [];
|
|
242
|
+
for (const file of WIDGET_SOURCE_FILES) {
|
|
243
|
+
const ref = xcodeProject.generateUuid();
|
|
244
|
+
pbxFileRef[ref] = {
|
|
245
|
+
isa: 'PBXFileReference',
|
|
246
|
+
lastKnownFileType: 'sourcecode.swift',
|
|
247
|
+
name: file.name,
|
|
248
|
+
path: file.name,
|
|
249
|
+
sourceTree: '"<group>"',
|
|
250
|
+
};
|
|
251
|
+
pbxFileRef[ref + '_comment'] = file.name;
|
|
252
|
+
sourceFileRefs.push({ ref, name: file.name });
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const plistRef = xcodeProject.generateUuid();
|
|
256
|
+
pbxFileRef[plistRef] = {
|
|
257
|
+
isa: 'PBXFileReference',
|
|
258
|
+
lastKnownFileType: 'text.plist.xml',
|
|
259
|
+
name: 'Info.plist',
|
|
260
|
+
path: 'Info.plist',
|
|
261
|
+
sourceTree: '"<group>"',
|
|
262
|
+
};
|
|
263
|
+
pbxFileRef[plistRef + '_comment'] = 'Info.plist';
|
|
264
|
+
|
|
265
|
+
const entRef = xcodeProject.generateUuid();
|
|
266
|
+
pbxFileRef[entRef] = {
|
|
267
|
+
isa: 'PBXFileReference',
|
|
268
|
+
lastKnownFileType: 'text.plist.entitlements',
|
|
269
|
+
name: `${EXTENSION_NAME}.entitlements`,
|
|
270
|
+
path: `${EXTENSION_NAME}.entitlements`,
|
|
271
|
+
sourceTree: '"<group>"',
|
|
272
|
+
};
|
|
273
|
+
pbxFileRef[entRef + '_comment'] = `${EXTENSION_NAME}.entitlements`;
|
|
274
|
+
|
|
275
|
+
const groupUuid = xcodeProject.generateUuid();
|
|
276
|
+
const pbxGroup = xcodeProject.hash.project.objects['PBXGroup'];
|
|
277
|
+
pbxGroup[groupUuid] = {
|
|
278
|
+
isa: 'PBXGroup',
|
|
279
|
+
children: [
|
|
280
|
+
...sourceFileRefs.map((f) => ({ value: f.ref, comment: f.name })),
|
|
281
|
+
{ value: plistRef, comment: 'Info.plist' },
|
|
282
|
+
{ value: entRef, comment: `${EXTENSION_NAME}.entitlements` },
|
|
283
|
+
],
|
|
284
|
+
name: EXTENSION_NAME,
|
|
285
|
+
path: EXTENSION_NAME,
|
|
286
|
+
sourceTree: '"<group>"',
|
|
287
|
+
};
|
|
288
|
+
pbxGroup[groupUuid + '_comment'] = EXTENSION_NAME;
|
|
289
|
+
|
|
290
|
+
const mainGroup = xcodeProject.getFirstProject().firstProject.mainGroup;
|
|
291
|
+
const mainGroupObj = pbxGroup[mainGroup];
|
|
292
|
+
if (mainGroupObj && mainGroupObj.children) {
|
|
293
|
+
mainGroupObj.children.push({ value: groupUuid, comment: EXTENSION_NAME });
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const pbxBuildFile = xcodeProject.hash.project.objects['PBXBuildFile'];
|
|
297
|
+
const buildFileEntries = sourceFileRefs.map((f) => {
|
|
298
|
+
const buildUuid = xcodeProject.generateUuid();
|
|
299
|
+
pbxBuildFile[buildUuid] = {
|
|
300
|
+
isa: 'PBXBuildFile',
|
|
301
|
+
fileRef: f.ref,
|
|
302
|
+
fileRef_comment: f.name,
|
|
303
|
+
};
|
|
304
|
+
pbxBuildFile[buildUuid + '_comment'] = `${f.name} in Sources`;
|
|
305
|
+
return { value: buildUuid, comment: `${f.name} in Sources` };
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
if (!xcodeProject.hash.project.objects['PBXSourcesBuildPhase']) {
|
|
309
|
+
xcodeProject.hash.project.objects['PBXSourcesBuildPhase'] = {};
|
|
310
|
+
}
|
|
311
|
+
const sourcesPhaseUuid = xcodeProject.generateUuid();
|
|
312
|
+
xcodeProject.hash.project.objects['PBXSourcesBuildPhase'][sourcesPhaseUuid] = {
|
|
313
|
+
isa: 'PBXSourcesBuildPhase',
|
|
314
|
+
buildActionMask: 2147483647,
|
|
315
|
+
files: buildFileEntries,
|
|
316
|
+
runOnlyForDeploymentPostprocessing: 0,
|
|
317
|
+
};
|
|
318
|
+
xcodeProject.hash.project.objects['PBXSourcesBuildPhase'][sourcesPhaseUuid + '_comment'] = 'Sources';
|
|
319
|
+
|
|
320
|
+
if (!xcodeProject.hash.project.objects['PBXFrameworksBuildPhase']) {
|
|
321
|
+
xcodeProject.hash.project.objects['PBXFrameworksBuildPhase'] = {};
|
|
322
|
+
}
|
|
323
|
+
const frameworksPhaseUuid = xcodeProject.generateUuid();
|
|
324
|
+
xcodeProject.hash.project.objects['PBXFrameworksBuildPhase'][frameworksPhaseUuid] = {
|
|
325
|
+
isa: 'PBXFrameworksBuildPhase',
|
|
326
|
+
buildActionMask: 2147483647,
|
|
327
|
+
files: [],
|
|
328
|
+
runOnlyForDeploymentPostprocessing: 0,
|
|
329
|
+
};
|
|
330
|
+
xcodeProject.hash.project.objects['PBXFrameworksBuildPhase'][frameworksPhaseUuid + '_comment'] = 'Frameworks';
|
|
331
|
+
|
|
332
|
+
if (!xcodeProject.hash.project.objects['PBXResourcesBuildPhase']) {
|
|
333
|
+
xcodeProject.hash.project.objects['PBXResourcesBuildPhase'] = {};
|
|
334
|
+
}
|
|
335
|
+
const resourcesPhaseUuid = xcodeProject.generateUuid();
|
|
336
|
+
xcodeProject.hash.project.objects['PBXResourcesBuildPhase'][resourcesPhaseUuid] = {
|
|
337
|
+
isa: 'PBXResourcesBuildPhase',
|
|
338
|
+
buildActionMask: 2147483647,
|
|
339
|
+
files: [],
|
|
340
|
+
runOnlyForDeploymentPostprocessing: 0,
|
|
341
|
+
};
|
|
342
|
+
xcodeProject.hash.project.objects['PBXResourcesBuildPhase'][resourcesPhaseUuid + '_comment'] = 'Resources';
|
|
343
|
+
|
|
344
|
+
const targetUuid = target.uuid;
|
|
345
|
+
const nativeTargets = xcodeProject.hash.project.objects['PBXNativeTarget'];
|
|
346
|
+
if (nativeTargets[targetUuid]) {
|
|
347
|
+
nativeTargets[targetUuid].buildPhases = [
|
|
348
|
+
{ value: sourcesPhaseUuid, comment: 'Sources' },
|
|
349
|
+
{ value: frameworksPhaseUuid, comment: 'Frameworks' },
|
|
350
|
+
{ value: resourcesPhaseUuid, comment: 'Resources' },
|
|
351
|
+
];
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const configurations = xcodeProject.pbxXCBuildConfigurationSection();
|
|
355
|
+
for (const key in configurations) {
|
|
356
|
+
const c = configurations[key];
|
|
357
|
+
if (c && typeof c === 'object' && c.name && c.buildSettings) {
|
|
358
|
+
if (
|
|
359
|
+
c.buildSettings.PRODUCT_NAME === `"${EXTENSION_NAME}"` ||
|
|
360
|
+
c.buildSettings.PRODUCT_NAME === EXTENSION_NAME
|
|
361
|
+
) {
|
|
362
|
+
c.buildSettings.IPHONEOS_DEPLOYMENT_TARGET = '16.2';
|
|
363
|
+
c.buildSettings.SWIFT_VERSION = '5.0';
|
|
364
|
+
c.buildSettings.CODE_SIGN_ENTITLEMENTS = `${EXTENSION_NAME}/${EXTENSION_NAME}.entitlements`;
|
|
365
|
+
c.buildSettings.INFOPLIST_FILE = `${EXTENSION_NAME}/Info.plist`;
|
|
366
|
+
c.buildSettings.PRODUCT_BUNDLE_IDENTIFIER = extensionBundleId;
|
|
367
|
+
c.buildSettings.GENERATE_INFOPLIST_FILE = 'NO';
|
|
368
|
+
c.buildSettings.CURRENT_PROJECT_VERSION = '1';
|
|
369
|
+
c.buildSettings.MARKETING_VERSION = '1.0';
|
|
370
|
+
c.buildSettings.CODE_SIGN_STYLE = 'Manual';
|
|
371
|
+
c.buildSettings.CODE_SIGN_IDENTITY = '"iPhone Distribution"';
|
|
372
|
+
c.buildSettings.SKIP_INSTALL = 'YES';
|
|
373
|
+
c.buildSettings.LD_RUNPATH_SEARCH_PATHS =
|
|
374
|
+
'"$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"';
|
|
375
|
+
|
|
376
|
+
for (const mk in configurations) {
|
|
377
|
+
const mc = configurations[mk];
|
|
378
|
+
if (
|
|
379
|
+
mc?.buildSettings?.DEVELOPMENT_TEAM &&
|
|
380
|
+
mc.name === c.name &&
|
|
381
|
+
mc.buildSettings.PRODUCT_BUNDLE_IDENTIFIER !== extensionBundleId
|
|
382
|
+
) {
|
|
383
|
+
c.buildSettings.DEVELOPMENT_TEAM = mc.buildSettings.DEVELOPMENT_TEAM;
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const mainTarget = xcodeProject.getFirstTarget();
|
|
392
|
+
if (mainTarget && mainTarget.firstTarget) {
|
|
393
|
+
xcodeProject.addTargetDependency(mainTarget.firstTarget.uuid, [target.uuid]);
|
|
394
|
+
const copyPhase = xcodeProject.addBuildPhase(
|
|
395
|
+
[],
|
|
396
|
+
'PBXCopyFilesBuildPhase',
|
|
397
|
+
'Embed App Extensions',
|
|
398
|
+
mainTarget.firstTarget.uuid,
|
|
399
|
+
'app_extension',
|
|
400
|
+
);
|
|
401
|
+
if (copyPhase) {
|
|
402
|
+
copyPhase.buildPhase.dstSubfolderSpec = 13;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return cfg;
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
return config;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// ─── Entry ───────────────────────────────────────────────────────────────────
|
|
413
|
+
|
|
414
|
+
function withSitePong(config, props = {}) {
|
|
415
|
+
// Device id privacy manifest is always safe to apply.
|
|
416
|
+
config = withDeviceIdPrivacy(config);
|
|
417
|
+
|
|
418
|
+
// Live Activities alter the Xcode project — opt in explicitly.
|
|
419
|
+
if (props && (props.liveActivities === true || props.appGroupId)) {
|
|
420
|
+
config = withLiveActivities(config, props);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
return config;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
module.exports = withSitePong;
|