Files
frontend/plugins/withSigning.js
lafay f3d54a3f4c
Some checks failed
Frontend CI / ota (android) (push) Has been cancelled
Frontend CI / ota (ios) (push) Has been cancelled
Frontend CI / build-and-push-web (push) Has been cancelled
Frontend CI / build-android-apk (push) Failing after 7m23s
feat(background): implement user consent mechanism for auto-start functionality
Add auto-start consent system that requires explicit user permission before enabling background sync services. Users can now choose between silent mode (no auto-start) or background mode (15-minute sync intervals).

- Add consent service with AutoStartMode enum and storage utilities
- Create withRemoveAutoStart Expo plugin to disable Android auto-start defaults
- Integrate consent checks into JPush service, background task manager, and foreground service
- Add auto-start consent UI in notification settings with descriptive dialog
- Update privacy policy with section 8 explaining auto-start scenarios and user controls
- Change default sync mode from BATTERY_SAVER to DISABLED
- Export reinitBackgroundService function for re-initializing after consent changes
- Merge OTA Android and iOS workflows into matrix build
- Add release signing config in withSigning plugin for Android
- Expand .dockerignore with native credential and build artifact exclusions
2026-06-15 20:43:15 +08:00

130 lines
4.6 KiB
JavaScript

const { withDangerousMod } = require('@expo/config-plugins');
const fs = require('fs');
const path = require('path');
const withSigning = (config, options = {}) => {
const { teamId = 'X3964MGXHG' } = options;
config = withDangerousMod(config, [
'ios',
async (config) => {
const platformRoot = config.modRequest.platformProjectRoot;
// 1. Inject CODE_SIGN_STYLE and DEVELOPMENT_TEAM into pbxproj
const pbxprojPath = path.join(platformRoot, 'app.xcodeproj', 'project.pbxproj');
if (fs.existsSync(pbxprojPath)) {
let contents = fs.readFileSync(pbxprojPath, 'utf-8');
const entitlementsLine = 'CODE_SIGN_ENTITLEMENTS = app/app.entitlements;';
const signingBlock = `${entitlementsLine}\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = ${teamId};`;
contents = contents.replaceAll(entitlementsLine, signingBlock);
fs.writeFileSync(pbxprojPath, contents);
}
// 2. Set aps-environment to production in entitlements
const entitlementsPath = path.join(platformRoot, 'app', 'app.entitlements');
if (fs.existsSync(entitlementsPath)) {
let entitlements = fs.readFileSync(entitlementsPath, 'utf-8');
entitlements = entitlements.replace(
/<key>aps-environment<\/key>\s*<string>development<\/string>/,
'<key>aps-environment</key>\n\t<string>production</string>'
);
fs.writeFileSync(entitlementsPath, entitlements);
}
return config;
},
]);
config = withDangerousMod(config, [
'android',
async (config) => {
const platformRoot = config.modRequest.platformProjectRoot;
const buildGradlePath = path.join(platformRoot, 'app', 'build.gradle');
if (!fs.existsSync(buildGradlePath)) return config;
let lines = fs.readFileSync(buildGradlePath, 'utf-8').split('\n');
// 1. Add release signing config that reads from gradle.properties
const hasReleaseSigning = lines.some((l) => l.includes('MYAPP_UPLOAD_STORE_FILE'));
if (!hasReleaseSigning) {
// Find the debug signingConfig closing brace and insert release after it
let debugBraceLine = -1;
let inSigningConfigs = false;
let braceDepth = 0;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.includes('signingConfigs {') || line.match(/^\s*signingConfigs\s*\{/)) {
inSigningConfigs = true;
braceDepth = 1;
continue;
}
if (inSigningConfigs) {
braceDepth += (line.match(/\{/g) || []).length;
braceDepth -= (line.match(/\}/g) || []).length;
if (braceDepth === 0) {
debugBraceLine = i; // This is the closing } of signingConfigs
break;
}
}
}
if (debugBraceLine > 0) {
const releaseBlock = [
' release {',
" if (project.hasProperty('MYAPP_UPLOAD_STORE_FILE')) {",
' storeFile file(MYAPP_UPLOAD_STORE_FILE)',
' storePassword MYAPP_UPLOAD_STORE_PASSWORD',
' keyAlias MYAPP_UPLOAD_KEY_ALIAS',
' keyPassword MYAPP_UPLOAD_KEY_PASSWORD',
' }',
' }',
];
lines.splice(debugBraceLine, 0, ...releaseBlock);
}
}
// 2. Change release buildType to use release signingConfig
// Walk through buildTypes > release and replace signingConfigs.debug -> signingConfigs.release
let inBuildTypes = false;
let inRelease = false;
let buildTypesDepth = 0;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.includes('buildTypes {') || line.match(/^\s*buildTypes\s*\{/)) {
inBuildTypes = true;
buildTypesDepth = 1;
continue;
}
if (inBuildTypes) {
buildTypesDepth += (line.match(/\{/g) || []).length;
buildTypesDepth -= (line.match(/\}/g) || []).length;
if (line.match(/^\s*release\s*\{/)) {
inRelease = true;
}
if (inRelease && line.includes('signingConfig signingConfigs.debug')) {
lines[i] = line.replace('signingConfig signingConfigs.debug', 'signingConfig signingConfigs.release');
inRelease = false;
}
if (buildTypesDepth === 0) {
inBuildTypes = false;
inRelease = false;
}
}
}
fs.writeFileSync(buildGradlePath, lines.join('\n'));
return config;
},
]);
return config;
};
module.exports = withSigning;