vxrn 2.0.0-beta.130.1 → 2.0.0-beta.131.1

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.
@@ -247,7 +247,7 @@ function patchIosPbxprojSceneDelegate(rendered, appName) {
247
247
  }
248
248
  return patched;
249
249
  }
250
- function patchIosPbxprojPushEntitlements(rendered, appName) {
250
+ function patchIosPbxprojAppEntitlements(rendered, appName) {
251
251
  const edits = [["/* AppDelegate.swift */ = {isa = PBXFileReference;", ` ${PUSH_ENTITLEMENTS_FILE_REF_ID} /* ${appName}.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = ${appName}.entitlements; path = ${appName}/${appName}.entitlements; sourceTree = "<group>"; };`], ["/* AppDelegate.swift */,", ` ${PUSH_ENTITLEMENTS_FILE_REF_ID} /* ${appName}.entitlements */,`]];
252
252
  let patched = rendered;
253
253
  for (const [anchor, insertion] of edits) {
@@ -264,13 +264,55 @@ function patchIosPbxprojPushEntitlements(rendered, appName) {
264
264
  return patched.split(setting).join(`${setting}
265
265
  CODE_SIGN_ENTITLEMENTS = ${appName}/${appName}.entitlements;`);
266
266
  }
267
- function renderPushEntitlements() {
267
+ function renderPlistValue(value, indent) {
268
+ if (typeof value === "string") return `${indent}<string>${escapeXml(value)}</string>`;
269
+ if (typeof value === "boolean") return `${indent}<${value}/>`;
270
+ if (typeof value === "number") {
271
+ return Number.isInteger(value) ? `${indent}<integer>${value}</integer>` : `${indent}<real>${value}</real>`;
272
+ }
273
+ if (Array.isArray(value)) {
274
+ return `${indent}<array>
275
+ ${value.map((item) => renderPlistValue(item, `${indent} `)).join("\n")}
276
+ ${indent}</array>`;
277
+ }
278
+ return `${indent}<dict>
279
+ ${renderPlistEntries(value, `${indent} `)}
280
+ ${indent}</dict>`;
281
+ }
282
+ function renderPlistEntries(entries, indent) {
283
+ return Object.entries(entries).map(([key, value]) => `${indent}<key>${escapeXml(key)}</key>
284
+ ${renderPlistValue(value, indent)}`).join("\n");
285
+ }
286
+ function appEntitlements(app) {
287
+ const modeled = {};
288
+ if (app.notifications?.push === true || app.ios?.widgets?.pushNotifications) {
289
+ modeled["aps-environment"] = notificationsHost.apsEnvironment;
290
+ }
291
+ if (app.ios?.widgets) {
292
+ modeled["com.apple.security.application-groups"] = [app.ios.widgets.appGroup];
293
+ }
294
+ if (app.ios?.associatedDomains?.length) {
295
+ modeled["com.apple.developer.associated-domains"] = app.ios.associatedDomains;
296
+ }
297
+ if (app.ios?.usesAppleSignIn) {
298
+ modeled["com.apple.developer.applesignin"] = ["Default"];
299
+ }
300
+ for (const key of Object.keys(app.ios?.entitlements ?? {})) {
301
+ if (key in modeled) {
302
+ throw new Error(`[vxrn] native.app.ios.entitlements sets ${key}, which native.app already writes: use its field`);
303
+ }
304
+ }
305
+ return {
306
+ ...modeled,
307
+ ...app.ios?.entitlements
308
+ };
309
+ }
310
+ function renderEntitlements(entries) {
268
311
  return `<?xml version="1.0" encoding="UTF-8"?>
269
312
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
270
313
  <plist version="1.0">
271
314
  <dict>
272
- <key>aps-environment</key>
273
- <string>${notificationsHost.apsEnvironment}</string>
315
+ ${renderPlistEntries(entries, " ")}
274
316
  </dict>
275
317
  </plist>
276
318
  `;
@@ -409,8 +451,9 @@ function generateSceneDelegate(args) {
409
451
  const { dest, platform, app } = args;
410
452
  if (platform !== "ios") return;
411
453
  FSExtra.writeFileSync(path.join(dest, app.name, "SceneDelegate.swift"), renderSceneDelegateSwift(app.name));
412
- if (app.notifications?.push === true && !app.ios?.widgets) {
413
- FSExtra.writeFileSync(path.join(dest, app.name, `${app.name}.entitlements`), renderPushEntitlements());
454
+ const entitlements = appEntitlements(app);
455
+ if (Object.keys(entitlements).length && !app.ios?.widgets) {
456
+ FSExtra.writeFileSync(path.join(dest, app.name, `${app.name}.entitlements`), renderEntitlements(entitlements));
414
457
  }
415
458
  }
416
459
  function generateIosWidgets(dest, app) {
@@ -423,7 +466,7 @@ function generateIosWidgets(dest, app) {
423
466
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
424
467
  <plist version="1.0"><dict><key>com.apple.security.application-groups</key><array><string>${escapeXml(widgets.appGroup)}</string></array></dict></plist>
425
468
  `;
426
- FSExtra.writeFileSync(path.join(appDir, "OneAppWidgets.entitlements"), widgets.pushNotifications || app.notifications?.push ? entitlements.replace("</dict></plist>", `<key>aps-environment</key><string>${notificationsHost.apsEnvironment}</string></dict></plist>`) : entitlements);
469
+ FSExtra.writeFileSync(path.join(appDir, "OneAppWidgets.entitlements"), renderEntitlements(appEntitlements(app)));
427
470
  FSExtra.writeFileSync(path.join(extensionDir, "OneWidgets.entitlements"), entitlements);
428
471
  FSExtra.writeFileSync(path.join(extensionDir, "WidgetInfo.plist"), `<?xml version="1.0" encoding="UTF-8"?>
429
472
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -1223,6 +1266,12 @@ ${schemes.map((scheme) => ` <string>${scheme}</string>`).join("\n")}
1223
1266
  ${phoneOrientations.map((orientation) => ` <string>${orientation}</string>`).join("\n")}
1224
1267
  </array>`);
1225
1268
  }
1269
+ for (const [key, value] of Object.entries(app.ios?.infoPlist ?? {})) {
1270
+ if (rendered.includes(`<key>${key}</key>`) || stamps.some((stamp) => stamp.includes(`<key>${key}</key>`))) {
1271
+ throw new Error(`[vxrn] native.app.ios.infoPlist sets ${key}, which the template or native.app already writes: use its field`);
1272
+ }
1273
+ stamps.push(renderPlistEntries({ [key]: value }, " "));
1274
+ }
1226
1275
  if (stamps.length) {
1227
1276
  const anchor = " <key>LSRequiresIPhoneOS</key>";
1228
1277
  if (!rendered.includes(anchor)) throw new Error(`[vxrn] prebuild template ${relativePath} lost its LSRequiresIPhoneOS anchor`);
@@ -1334,6 +1383,29 @@ ${line}
1334
1383
  }
1335
1384
  rendered = rendered.replace(dayNight, app.userInterfaceStyle === "light" ? "parent=\"Theme.AppCompat.Light.NoActionBar\"" : "parent=\"Theme.AppCompat.NoActionBar\"");
1336
1385
  }
1386
+ if (platform === "android" && relativePath === "app/src/main/AndroidManifest.xml" && (app.android?.permissions?.length || app.android?.blockedPermissions?.length)) {
1387
+ const anchor = "<uses-permission android:name=\"android.permission.INTERNET\" />";
1388
+ if (!rendered.includes(anchor)) {
1389
+ throw new Error("[vxrn] cannot stamp permissions: expected the INTERNET permission in app/src/main/AndroidManifest.xml");
1390
+ }
1391
+ const permissionName = (name) => name.includes(".") ? name : `android.permission.${name}`;
1392
+ const lines = [...(app.android?.permissions ?? []).map((name) => ` <uses-permission android:name="${permissionName(name)}" />`), ...(app.android?.blockedPermissions ?? []).map((name) => ` <uses-permission android:name="${permissionName(name)}" tools:node="remove" />`)];
1393
+ rendered = rendered.replace(anchor, `${anchor}
1394
+ ${lines.join("\n")}`);
1395
+ if (app.android?.blockedPermissions?.length && !rendered.includes("xmlns:tools=")) {
1396
+ rendered = rendered.replace("xmlns:android=\"http://schemas.android.com/apk/res/android\"", "xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xmlns:tools=\"http://schemas.android.com/tools\"");
1397
+ }
1398
+ }
1399
+ if (platform === "android" && relativePath === "app/src/main/AndroidManifest.xml" && app.android?.appLinks?.length) {
1400
+ rendered = rendered.replace(" </activity>", ` <intent-filter android:autoVerify="true">
1401
+ <action android:name="android.intent.action.VIEW" />
1402
+ <category android:name="android.intent.category.DEFAULT" />
1403
+ <category android:name="android.intent.category.BROWSABLE" />
1404
+ <data android:scheme="https" />
1405
+ ${app.android.appLinks.map((link) => ` <data android:host="${link.host}"${link.pathPrefix ? ` android:pathPrefix="${link.pathPrefix}"` : ""} />`).join("\n")}
1406
+ </intent-filter>
1407
+ </activity>`);
1408
+ }
1337
1409
  if (platform === "android" && relativePath === "app/src/main/AndroidManifest.xml" && app.orientation !== void 0) {
1338
1410
  const anchor = "android:name=\".MainActivity\"";
1339
1411
  if (!rendered.includes(anchor)) {
@@ -1447,8 +1519,8 @@ end`);
1447
1519
  rendered = patchIosBundlePhase(rendered, app.updates?.runtimeVersion);
1448
1520
  rendered = patchIosPbxprojSceneDelegate(rendered, appName);
1449
1521
  rendered = patchIosPbxprojOneBridgingHeader(rendered, appName);
1450
- if (app.notifications?.push === true && !app.ios?.widgets) {
1451
- rendered = patchIosPbxprojPushEntitlements(rendered, appName);
1522
+ if (Object.keys(appEntitlements(app)).length && !app.ios?.widgets) {
1523
+ rendered = patchIosPbxprojAppEntitlements(rendered, appName);
1452
1524
  }
1453
1525
  if (app.ios?.widgets) rendered = patchIosPbxprojWidgets(rendered, app);
1454
1526
  }
@@ -1493,8 +1565,14 @@ use_frameworks! :linkage => :${app.ios.useFrameworks}`);
1493
1565
  }
1494
1566
  rendered = rendered.replace(hardcodedGradlePlugin, `includeBuild(new File(["node", "--print", "require('module').createRequire(require.resolve('react-native/package.json')).resolve('@react-native/gradle-plugin/package.json')"].execute(null, settingsDir).text.trim()).parentFile.canonicalPath)`);
1495
1567
  }
1496
- if (platform === "android" && app.android?.minSdk !== void 0) {
1497
- rendered = rendered.replace(/minSdkVersion = \d+/g, `minSdkVersion = ${app.android.minSdk}`);
1568
+ for (const [field, setting] of [
1569
+ ["minSdk", "minSdkVersion"],
1570
+ ["targetSdk", "targetSdkVersion"],
1571
+ ["compileSdk", "compileSdkVersion"]
1572
+ ]) {
1573
+ const value = platform === "android" ? app.android?.[field] : void 0;
1574
+ if (value === void 0) continue;
1575
+ rendered = rendered.replace(new RegExp(`${setting} = \\d+`, "g"), `${setting} = ${value}`);
1498
1576
  }
1499
1577
  }
1500
1578
  return {