193 lines
5.6 KiB
Plaintext
193 lines
5.6 KiB
Plaintext
|
// Copyright 2015-present 650 Industries. All rights reserved.
|
||
|
/**
|
||
|
* @flow
|
||
|
*/
|
||
|
|
||
|
'use strict';
|
||
|
|
||
|
// Set EXPO_VIEW_DIR to universe/exponent to test locally
|
||
|
|
||
|
import mkdirp from 'mkdirp';
|
||
|
import fs from 'fs-extra';
|
||
|
import path from 'path';
|
||
|
import rimraf from 'rimraf';
|
||
|
import glob from 'glob-promise';
|
||
|
|
||
|
import {
|
||
|
saveImageToPathAsync,
|
||
|
rimrafDontThrow,
|
||
|
} from './ExponentTools';
|
||
|
|
||
|
import Api from '../Api';
|
||
|
import * as Utils from '../Utils';
|
||
|
|
||
|
const ANDROID_TEMPLATE_PKG = 'detach.app.template.pkg.name';
|
||
|
const ANDROID_TEMPLATE_NAME = 'DetachAppTemplate';
|
||
|
|
||
|
async function regexFileAsync(filename, regex, replace) {
|
||
|
let file = await fs.readFile(filename);
|
||
|
let fileString = file.toString();
|
||
|
await fs.writeFile(filename, fileString.replace(regex, replace));
|
||
|
}
|
||
|
|
||
|
async function renamePackageAsync(directory, originalPkg, destPkg) {
|
||
|
let originalSplitPackage = originalPkg.split('.');
|
||
|
let originalDeepDirectory = directory;
|
||
|
for (let i = 0; i < originalSplitPackage.length; i++) {
|
||
|
originalDeepDirectory = path.join(originalDeepDirectory, originalSplitPackage[i]);
|
||
|
}
|
||
|
|
||
|
// copy files into temp directory
|
||
|
let tmpDirectory = path.join(directory, 'tmp-exponent-directory');
|
||
|
mkdirp.sync(tmpDirectory);
|
||
|
await Utils.ncpAsync(originalDeepDirectory, tmpDirectory);
|
||
|
|
||
|
// delete old package
|
||
|
rimraf.sync(path.join(directory, originalSplitPackage[0]));
|
||
|
|
||
|
// make new package
|
||
|
let newSplitPackage = destPkg.split('.');
|
||
|
let newDeepDirectory = directory;
|
||
|
for (let i = 0; i < newSplitPackage.length; i++) {
|
||
|
newDeepDirectory = path.join(newDeepDirectory, newSplitPackage[i]);
|
||
|
mkdirp.sync(newDeepDirectory);
|
||
|
}
|
||
|
|
||
|
// copy from temp to new package
|
||
|
await Utils.ncpAsync(tmpDirectory, newDeepDirectory);
|
||
|
|
||
|
// delete temp
|
||
|
rimraf.sync(tmpDirectory);
|
||
|
}
|
||
|
|
||
|
export async function detachAndroidAsync(
|
||
|
projectRoot,
|
||
|
expoDirectory,
|
||
|
sdkVersion,
|
||
|
experienceUrl,
|
||
|
manifest,
|
||
|
expoViewUrl: string
|
||
|
) {
|
||
|
let tmpExpoDirectory;
|
||
|
if (process.env.EXPO_VIEW_DIR) {
|
||
|
// Only for testing
|
||
|
tmpExpoDirectory = process.env.EXPO_VIEW_DIR;
|
||
|
} else {
|
||
|
tmpExpoDirectory = path.join(projectRoot, 'temp-android-directory');
|
||
|
mkdirp.sync(tmpExpoDirectory);
|
||
|
console.log('Downloading Android code...');
|
||
|
await Api.downloadAsync(expoViewUrl, tmpExpoDirectory, { extract: true });
|
||
|
}
|
||
|
|
||
|
let androidProjectDirectory = path.join(projectRoot, 'android');
|
||
|
|
||
|
console.log('Moving Android project files...');
|
||
|
|
||
|
await Utils.ncpAsync(
|
||
|
path.join(tmpExpoDirectory, 'android', 'maven'),
|
||
|
path.join(expoDirectory, 'maven')
|
||
|
);
|
||
|
await Utils.ncpAsync(
|
||
|
path.join(tmpExpoDirectory, 'android', 'detach-scripts'),
|
||
|
path.join(expoDirectory, 'detach-scripts')
|
||
|
);
|
||
|
await Utils.ncpAsync(
|
||
|
path.join(tmpExpoDirectory, 'exponent-view-template', 'android'),
|
||
|
androidProjectDirectory
|
||
|
);
|
||
|
if (process.env.EXPO_VIEW_DIR) {
|
||
|
rimraf.sync(path.join(androidProjectDirectory, 'build'));
|
||
|
rimraf.sync(path.join(androidProjectDirectory, 'app', 'build'));
|
||
|
}
|
||
|
|
||
|
// Fix up app/build.gradle
|
||
|
console.log('Configuring Android project...');
|
||
|
let appBuildGradle = path.join(androidProjectDirectory, 'app', 'build.gradle');
|
||
|
await regexFileAsync(appBuildGradle, /\/\* UNCOMMENT WHEN DISTRIBUTING/g, '');
|
||
|
await regexFileAsync(appBuildGradle, /END UNCOMMENT WHEN DISTRIBUTING \*\//g, '');
|
||
|
await regexFileAsync(appBuildGradle, `compile project(':expoview')`, '');
|
||
|
|
||
|
// Fix AndroidManifest
|
||
|
let androidManifest = path.join(
|
||
|
androidProjectDirectory,
|
||
|
'app',
|
||
|
'src',
|
||
|
'main',
|
||
|
'AndroidManifest.xml'
|
||
|
);
|
||
|
await regexFileAsync(androidManifest, 'PLACEHOLDER_DETACH_SCHEME', manifest.detach.scheme);
|
||
|
|
||
|
// Fix MainActivity
|
||
|
let mainActivity = path.join(
|
||
|
androidProjectDirectory,
|
||
|
'app',
|
||
|
'src',
|
||
|
'main',
|
||
|
'java',
|
||
|
'detach',
|
||
|
'app',
|
||
|
'template',
|
||
|
'pkg',
|
||
|
'name',
|
||
|
'MainActivity.java'
|
||
|
);
|
||
|
await regexFileAsync(mainActivity, 'TEMPLATE_INITIAL_URL', experienceUrl);
|
||
|
|
||
|
// Fix package name
|
||
|
let packageName = manifest.android.package;
|
||
|
await renamePackageAsync(
|
||
|
path.join(androidProjectDirectory, 'app', 'src', 'main', 'java'),
|
||
|
ANDROID_TEMPLATE_PKG,
|
||
|
packageName
|
||
|
);
|
||
|
await renamePackageAsync(
|
||
|
path.join(androidProjectDirectory, 'app', 'src', 'test', 'java'),
|
||
|
ANDROID_TEMPLATE_PKG,
|
||
|
packageName
|
||
|
);
|
||
|
await renamePackageAsync(
|
||
|
path.join(androidProjectDirectory, 'app', 'src', 'androidTest', 'java'),
|
||
|
ANDROID_TEMPLATE_PKG,
|
||
|
packageName
|
||
|
);
|
||
|
|
||
|
let packageNameMatches = await glob(androidProjectDirectory + '/**/*.@(java|gradle|xml)');
|
||
|
if (packageNameMatches) {
|
||
|
let oldPkgRegex = new RegExp(`${ANDROID_TEMPLATE_PKG.replace(/\./g, '\\.')}`, 'g');
|
||
|
for (let i = 0; i < packageNameMatches.length; i++) {
|
||
|
await regexFileAsync(packageNameMatches[i], oldPkgRegex, packageName);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Fix app name
|
||
|
console.log('Naming Android project...');
|
||
|
let appName = manifest.name;
|
||
|
await regexFileAsync(
|
||
|
path.resolve(androidProjectDirectory, 'app', 'src', 'main', 'res', 'values', 'strings.xml'),
|
||
|
ANDROID_TEMPLATE_NAME,
|
||
|
appName
|
||
|
);
|
||
|
|
||
|
// Fix image
|
||
|
let icon = manifest.android && manifest.android.icon ? manifest.android.icon : manifest.icon;
|
||
|
if (icon) {
|
||
|
let iconMatches = await glob(
|
||
|
path.join(androidProjectDirectory, 'app', 'src', 'main', 'res') + '/**/ic_launcher.png'
|
||
|
);
|
||
|
if (iconMatches) {
|
||
|
for (let i = 0; i < iconMatches.length; i++) {
|
||
|
await fs.unlink(iconMatches[i]);
|
||
|
// TODO: make more efficient
|
||
|
await saveImageToPathAsync(projectRoot, icon, iconMatches[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Clean up
|
||
|
console.log('Cleaning up Android...');
|
||
|
if (!process.env.EXPO_VIEW_DIR) {
|
||
|
rimrafDontThrow(tmpExpoDirectory);
|
||
|
}
|
||
|
console.log('Android detach is complete!\n');
|
||
|
}
|