Files
pleno-vue/scripts/mobile/check-permissions.mjs
T
Jeppe B 32418b42a0 fix(ios): add required location purpose string (#223)
## What changed
- add `NSLocationAlwaysAndWhenInUseUsageDescription` to the iOS app
- localize the purpose string in Danish and English
- enforce the key in mobile permission validation and App Store
readiness tests

## Why
App Store Connect accepted builds 1 and 2 but emitted `ITMS-90683`,
stating that the final app references APIs requiring this purpose
string. Shipping a corrected binary avoids submitting a candidate with a
known Apple delivery warning.

## Validation
- `node scripts/mobile/check-permissions.mjs`
- `node scripts/mobile/validate-app-store.mjs --strict`
- `vitest run tests/unit/app-store-product-readiness.spec.js` (5 tests)
- Prettier check for changed JS files
- `git diff --check`
2026-07-23 16:36:35 +00:00

47 lines
2.2 KiB
JavaScript

import { readFileSync } from "node:fs";
import { join } from "node:path";
import { cwd, exit } from "node:process";
const projectRoot = cwd();
const readText = (relativePath) => readFileSync(join(projectRoot, relativePath), "utf8");
const failures = [];
const requireText = (label, contents, expected) => {
if (!contents.includes(expected)) {
failures.push(`${label} is missing ${expected}`);
}
};
const androidManifest = readText("android/app/src/main/AndroidManifest.xml");
const androidBuild = readText("android/app/build.gradle");
const iosInfoPlist = readText("ios/App/App/Info.plist");
const iosProject = readText("ios/App/App.xcodeproj/project.pbxproj");
const iosPrivacyManifest = readText("ios/App/App/PrivacyInfo.xcprivacy");
requireText("AndroidManifest.xml", androidManifest, "android.permission.CAMERA");
requireText("AndroidManifest.xml", androidManifest, "android.permission.ACCESS_COARSE_LOCATION");
requireText("AndroidManifest.xml", androidManifest, "android.permission.ACCESS_FINE_LOCATION");
requireText("AndroidManifest.xml", androidManifest, 'android:name="android.hardware.camera"');
requireText("AndroidManifest.xml", androidManifest, 'android:name="android.hardware.location.gps"');
requireText("AndroidManifest.xml", androidManifest, 'android:required="false"');
requireText("android/app/build.gradle", androidBuild, 'applicationId "io.truckwash.twa"');
requireText("android/app/build.gradle", androidBuild, "ANDROID_KEYSTORE_FILE");
requireText("Info.plist", iosInfoPlist, "NSCameraUsageDescription");
requireText("Info.plist", iosInfoPlist, "NSLocationAlwaysAndWhenInUseUsageDescription");
requireText("Info.plist", iosInfoPlist, "NSLocationWhenInUseUsageDescription");
requireText("project.pbxproj", iosProject, "PRODUCT_BUNDLE_IDENTIFIER = io.truckwash.app;");
requireText("project.pbxproj", iosProject, "PrivacyInfo.xcprivacy in Resources");
requireText("PrivacyInfo.xcprivacy", iosPrivacyManifest, "NSPrivacyCollectedDataTypes");
requireText("PrivacyInfo.xcprivacy", iosPrivacyManifest, "NSPrivacyTracking");
if (failures.length > 0) {
console.error("Mobile permission validation failed:");
for (const failure of failures) {
console.error(`- ${failure}`);
}
exit(1);
}
console.log("Mobile permission validation passed.");