mirror of
https://github.com/Boof2015/astra-mobile.git
synced 2026-08-12 05:10:52 +02:00
245 lines
9.2 KiB
JavaScript
245 lines
9.2 KiB
JavaScript
const fs = require('fs/promises');
|
|
const path = require('path');
|
|
const {
|
|
AndroidConfig,
|
|
withDangerousMod,
|
|
withAndroidManifest,
|
|
withAppBuildGradle,
|
|
withProjectBuildGradle,
|
|
withSettingsGradle,
|
|
} = require('expo/config-plugins');
|
|
|
|
const SETTINGS_MARKER = '// ASTRA VENDORED KOTLIN AUDIO';
|
|
const PROJECT_BUILD_MARKER = '// ASTRA KOTLIN AUDIO SUBSTITUTION';
|
|
const SIGNING_MARKER = '// ASTRA RELEASE SIGNING';
|
|
const CAMERA_FEATURE = 'android.hardware.camera';
|
|
const NOTIFICATION_ICON_FILE = 'astra_notification_icon.xml';
|
|
const NOTIFICATION_OVERRIDE_FILE = 'astra_notification_icon_overrides.xml';
|
|
|
|
// A notification small icon is an alpha mask: Android supplies the color for
|
|
// the status bar, lock screen and media controls. Keep only the main Astra mark
|
|
// here—launcher backgrounds, shadows and brand colors do not belong in it.
|
|
const NOTIFICATION_ICON_VECTOR = `<?xml version="1.0" encoding="utf-8"?>
|
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
android:width="24dp"
|
|
android:height="24dp"
|
|
android:viewportWidth="1024"
|
|
android:viewportHeight="1024">
|
|
<group
|
|
android:scaleX="1.726813"
|
|
android:scaleY="1.726813"
|
|
android:translateX="-660.505902"
|
|
android:translateY="-373.7">
|
|
<path
|
|
android:fillColor="#FFFFFFFF"
|
|
android:pathData="M526.083,500.65C529.86,496.662 535.112,494.402 540.605,494.402C553.071,494.402 576.056,494.402 588.831,494.402C594.652,494.402 600.185,496.939 603.984,501.35C610.054,508.396 619.61,519.49 627.207,528.31C633.905,536.085 633.631,547.668 626.573,555.117C603.295,579.689 553.937,631.788 536.916,649.755C533.139,653.742 527.889,656 522.397,656L452,656C440.954,656 432,647.046 432,636C432,626.32 432,615.247 432,607.967C432,602.851 433.96,597.93 437.478,594.215C454.783,575.942 508.184,519.551 526.083,500.65Z" />
|
|
<path
|
|
android:fillColor="#FFFFFFFF"
|
|
android:pathData="M580,389.237C580,378.578 588.641,369.937 599.3,369.937C625.097,369.937 669.782,369.937 688.899,369.937C694.682,369.937 700.183,372.436 703.987,376.792C736.676,414.222 893.163,593.401 921.571,625.929C924.427,629.198 926,633.392 926,637.733C926,637.733 926,637.734 926,637.734C926,648.379 917.371,657.008 906.726,657.008L817.1,657.008C811.318,657.008 805.817,654.51 802.013,650.155C769.332,612.742 612.909,433.673 584.448,401.092C581.58,397.809 580,393.598 580,389.239C580,389.238 580,389.237 580,389.237Z" />
|
|
</group>
|
|
</vector>
|
|
`;
|
|
|
|
// RNTP 4.1.2 uses ExoPlayer's generic circular-play drawable whenever no JS
|
|
// icon resolves. An app-level resource with the same name overrides that
|
|
// default in release, debug and the temporary foreground-service notification.
|
|
const NOTIFICATION_ICON_OVERRIDE = `<?xml version="1.0" encoding="utf-8"?>
|
|
<resources>
|
|
<item name="exo_notification_small_icon" type="drawable">@drawable/astra_notification_icon</item>
|
|
</resources>
|
|
`;
|
|
|
|
const SETTINGS_BLOCK = `
|
|
|
|
${SETTINGS_MARKER}
|
|
include ':kotlin-audio'
|
|
project(':kotlin-audio').projectDir = new File(rootDir, '../vendor/kotlinaudio/kotlin-audio')
|
|
`;
|
|
|
|
const PROJECT_BUILD_BLOCK = `
|
|
|
|
${PROJECT_BUILD_MARKER}
|
|
subprojects {
|
|
configurations.configureEach {
|
|
resolutionStrategy.dependencySubstitution {
|
|
substitute module('com.github.doublesymmetry:kotlinaudio') using project(':kotlin-audio')
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
|
|
const SIGNING_CONFIGURATION = `${SIGNING_MARKER}
|
|
def astraReleaseStorePath = System.getenv('ASTRA_ANDROID_KEYSTORE_PATH')
|
|
def astraReleaseStorePassword = System.getenv('ASTRA_ANDROID_KEYSTORE_PASSWORD')
|
|
def astraReleaseKeyAlias = System.getenv('ASTRA_ANDROID_KEY_ALIAS')
|
|
def astraReleaseKeyPassword = System.getenv('ASTRA_ANDROID_KEY_PASSWORD')
|
|
def astraAllowInsecureReleaseSigning = (System.getenv('ASTRA_ALLOW_INSECURE_RELEASE_SIGNING') ?: 'false').toBoolean()
|
|
def astraReleaseSigningValues = [
|
|
astraReleaseStorePath,
|
|
astraReleaseStorePassword,
|
|
astraReleaseKeyAlias,
|
|
astraReleaseKeyPassword,
|
|
]
|
|
def astraReleaseSigningConfigured = astraReleaseSigningValues.every { value -> value != null && !value.trim().isEmpty() }
|
|
|
|
gradle.taskGraph.whenReady { taskGraph ->
|
|
def astraReleaseTaskRequested = taskGraph.allTasks.any { task -> task.name.toLowerCase().contains('release') }
|
|
if (astraReleaseTaskRequested && !astraReleaseSigningConfigured && !astraAllowInsecureReleaseSigning) {
|
|
throw new GradleException('Release signing is not configured. Supply the ASTRA_ANDROID_KEYSTORE_* variables, or explicitly set ASTRA_ALLOW_INSECURE_RELEASE_SIGNING=true for a non-publishable local preview.')
|
|
}
|
|
}
|
|
|
|
if (astraReleaseSigningConfigured && !file(astraReleaseStorePath).isFile()) {
|
|
throw new GradleException('ASTRA_ANDROID_KEYSTORE_PATH does not point to a file: ' + astraReleaseStorePath)
|
|
}
|
|
`;
|
|
|
|
const RELEASE_SIGNING_CONFIG = ` if (astraReleaseSigningConfigured) {
|
|
release {
|
|
storeFile file(astraReleaseStorePath)
|
|
storePassword astraReleaseStorePassword
|
|
keyAlias astraReleaseKeyAlias
|
|
keyPassword astraReleaseKeyPassword
|
|
}
|
|
}
|
|
`;
|
|
|
|
function appendBlock(contents, marker, block) {
|
|
return contents.includes(marker) ? contents : `${contents.trimEnd()}${block}`;
|
|
}
|
|
|
|
function addReleaseSigning(contents) {
|
|
if (contents.includes(SIGNING_MARKER)) return contents;
|
|
|
|
const androidAnchor = 'android {';
|
|
const signingAnchor = ' signingConfigs {\n debug {';
|
|
const debugSigning = 'signingConfig signingConfigs.debug';
|
|
|
|
if (!contents.includes(androidAnchor)) {
|
|
throw new Error('Unable to add Astra release signing: android block was not found.');
|
|
}
|
|
if (!contents.includes(signingAnchor)) {
|
|
throw new Error('Unable to add Astra release signing: signingConfigs debug block was not found.');
|
|
}
|
|
|
|
let result = contents.replace(androidAnchor, `${SIGNING_CONFIGURATION}\n${androidAnchor}`);
|
|
result = result.replace(
|
|
signingAnchor,
|
|
` signingConfigs {\n${RELEASE_SIGNING_CONFIG} debug {`
|
|
);
|
|
|
|
const lastDebugSigning = result.lastIndexOf(debugSigning);
|
|
if (lastDebugSigning < 0) {
|
|
throw new Error('Unable to add Astra release signing: release signing assignment was not found.');
|
|
}
|
|
|
|
return `${result.slice(0, lastDebugSigning)}signingConfig astraReleaseSigningConfigured ? signingConfigs.release : signingConfigs.debug${result.slice(lastDebugSigning + debugSigning.length)}`;
|
|
}
|
|
|
|
function withVendoredKotlinAudio(config) {
|
|
config = withSettingsGradle(config, (mod) => {
|
|
mod.modResults.contents = appendBlock(mod.modResults.contents, SETTINGS_MARKER, SETTINGS_BLOCK);
|
|
return mod;
|
|
});
|
|
|
|
return withProjectBuildGradle(config, (mod) => {
|
|
mod.modResults.contents = appendBlock(
|
|
mod.modResults.contents,
|
|
PROJECT_BUILD_MARKER,
|
|
PROJECT_BUILD_BLOCK
|
|
);
|
|
return mod;
|
|
});
|
|
}
|
|
|
|
function withReleaseSigning(config) {
|
|
return withAppBuildGradle(config, (mod) => {
|
|
mod.modResults.contents = addReleaseSigning(mod.modResults.contents);
|
|
return mod;
|
|
});
|
|
}
|
|
|
|
function withProfileableRelease(config) {
|
|
return withAndroidManifest(config, (mod) => {
|
|
AndroidConfig.Manifest.ensureToolsAvailable(mod.modResults);
|
|
ensureOptionalCameraFeature(mod.modResults);
|
|
const application = AndroidConfig.Manifest.getMainApplicationOrThrow(mod.modResults);
|
|
application.profileable = [
|
|
{
|
|
$: {
|
|
'android:shell': 'true',
|
|
'tools:targetApi': '29',
|
|
},
|
|
},
|
|
];
|
|
return mod;
|
|
});
|
|
}
|
|
|
|
function ensureOptionalCameraFeature(androidManifest) {
|
|
const manifest = androidManifest.manifest;
|
|
const features = manifest['uses-feature'] ?? [];
|
|
const cameraFeature = features.find(
|
|
(feature) => feature.$?.['android:name'] === CAMERA_FEATURE
|
|
);
|
|
|
|
if (cameraFeature) {
|
|
cameraFeature.$['android:required'] = 'false';
|
|
} else {
|
|
features.push({
|
|
$: {
|
|
'android:name': CAMERA_FEATURE,
|
|
'android:required': 'false',
|
|
},
|
|
});
|
|
}
|
|
manifest['uses-feature'] = features;
|
|
}
|
|
|
|
async function writeNotificationIconResources(platformProjectRoot) {
|
|
const resourceRoot = path.join(platformProjectRoot, 'app', 'src', 'main', 'res');
|
|
const drawableDir = path.join(resourceRoot, 'drawable');
|
|
const valuesDir = path.join(resourceRoot, 'values');
|
|
|
|
await Promise.all([
|
|
fs.mkdir(drawableDir, { recursive: true }),
|
|
fs.mkdir(valuesDir, { recursive: true }),
|
|
]);
|
|
await Promise.all([
|
|
fs.writeFile(path.join(drawableDir, NOTIFICATION_ICON_FILE), NOTIFICATION_ICON_VECTOR),
|
|
fs.writeFile(path.join(valuesDir, NOTIFICATION_OVERRIDE_FILE), NOTIFICATION_ICON_OVERRIDE),
|
|
]);
|
|
}
|
|
|
|
function withAstraNotificationIcon(config) {
|
|
return withDangerousMod(config, [
|
|
'android',
|
|
async (mod) => {
|
|
await writeNotificationIconResources(mod.modRequest.platformProjectRoot);
|
|
return mod;
|
|
},
|
|
]);
|
|
}
|
|
|
|
function withAstraAndroidRelease(config) {
|
|
config = withVendoredKotlinAudio(config);
|
|
config = withReleaseSigning(config);
|
|
config = withAstraNotificationIcon(config);
|
|
return withProfileableRelease(config);
|
|
}
|
|
|
|
module.exports = withAstraAndroidRelease;
|
|
module.exports._internal = {
|
|
PROJECT_BUILD_MARKER,
|
|
SETTINGS_MARKER,
|
|
SIGNING_MARKER,
|
|
NOTIFICATION_ICON_FILE,
|
|
NOTIFICATION_ICON_VECTOR,
|
|
NOTIFICATION_OVERRIDE_FILE,
|
|
NOTIFICATION_ICON_OVERRIDE,
|
|
addReleaseSigning,
|
|
appendBlock,
|
|
ensureOptionalCameraFeature,
|
|
writeNotificationIconResources,
|
|
};
|