Skip to content

Commit

Permalink
feat: improve android build and run app with flavor
Browse files Browse the repository at this point in the history
  • Loading branch information
rams23 committed Feb 27, 2023
1 parent 6ca36ff commit a5bf889
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 35 deletions.
7 changes: 7 additions & 0 deletions src/application/androidUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {getAppName, getRootDestinationFolder} from './utils'

export function getAppBuildFolder(buildType: string) {
// todo add debug
const appPath = `${getRootDestinationFolder()}/android/${buildType}/debug`
return appPath
}
41 changes: 23 additions & 18 deletions src/application/buildAndroid.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
import path from "path";
import path from 'path'
import {executeCommand, getAppName, getProjectRootDir, getRootDestinationFolder} from './utils'
import {getAndroidFlavors} from './config'
import {getAppBuildFolder} from './androidUtils'

function capitalize(str: string) {
return str
}


const androidBuildConfig = {
"dev": {
"config": "debug"
}
export function buildAndroid(buildType: string) {
// todo improve flavor management with debug and release and no flavor usage
const buildFlavor = getAndroidFlavors(buildType)
if (!buildFlavor) {
throw new Error(`No android flavor found for ${buildType}`)
}
;
const {gradleFlavor} = buildFlavor

export function buildAndroid(buildType: keyof typeof androidBuildConfig) {
const { config } = androidBuildConfig[buildType];
const androidFolder = path.join(getProjectRootDir(), 'android')
// todo handle Debug/release

const androidFolder = path.join(getProjectRootDir(), "android");
const gradleBuildTask = (gradleFlavor && gradleFlavor !== 'debug') ? `install${capitalize(gradleFlavor)}Debug` : 'installDebug'

executeCommand(`${androidFolder}/gradlew \
/* executeCommand(`${androidFolder}/gradlew \
-Duser.dir=${androidFolder} \
app:assemble${config} \
`, { stdio: "inherit" });
app:${gradleBuildTask} \
`, {stdio: 'inherit'}) */

const destinationDir = `${getRootDestinationFolder()}/android/${buildType}`;
executeCommand(`rm -rf ${destinationDir} && mkdir -p ${destinationDir}`);
const app = `${androidFolder}/app/build/outputs/apk/${config}/app-${config}.apk`;
const destinationApp = `${destinationDir}/${getAppName()}.apk`;
executeCommand(`cp -a ${app} ${destinationApp}`);
const destinationDir = getAppBuildFolder(buildType)
executeCommand(`rm -rf ${destinationDir} && mkdir -p ${destinationDir}`)
const destinationFlavorFolder = (gradleFlavor && gradleFlavor !== 'debug') ? `${gradleFlavor}/debug` : 'debug'
const gradleOutputDir = `${androidFolder}/app/build/outputs/apk/${destinationFlavorFolder}/`
executeCommand(`cp -R ${gradleOutputDir} ${destinationDir}`)
}
29 changes: 27 additions & 2 deletions src/application/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ export type Config = {
flavorDir: string;
}
}
},
android?: {
flavors?: {
[key: string]: {
gradleFlavor: string;
}
}
}
}

Expand All @@ -27,6 +34,13 @@ function getDefaultConfig(): Config {
},
},
},
android: {
flavors: {
dev: {
gradleFlavor: 'debug',
},
},
},
}
}

Expand All @@ -44,8 +58,19 @@ export function loadConfig() {

const config = loadConfig()

export function getIosFlavors(flavorName:string) {
return config.ios.flavors[flavorName];
export function getIosFlavors(flavorName: string) {
return config.ios.flavors[flavorName]
}

export function getAndroidFlavors(flavorName: string) {
const flavorConfig = config?.android?.flavors?.[flavorName];
if(flavorConfig){
return flavorConfig;
}else {
return {
gradleFlavor: flavorName,
}
}
}

export default config
67 changes: 54 additions & 13 deletions src/application/runAndroid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import adb from '@react-native-community/cli-platform-android/build/commands/run
import _getAdbPath from '@react-native-community/cli-platform-android/build/commands/runAndroid/getAdbPath'
import tryLaunchEmulator from '@react-native-community/cli-platform-android/build/commands/runAndroid/tryLaunchEmulator'
import {buildAndroid} from './buildAndroid'
import {getAppBuildFolder} from './androidUtils'
import path from 'path'

function getAdbPath() {
const androidHome = process.env.ANDROID_HOME
Expand All @@ -29,20 +31,43 @@ function getBootedDevices() {
return String(output).trim().split('\n')
}

function getBuildFolder(buildType: string) {
const appPath = `${getRootDestinationFolder()}/android/${buildType}/${getAppName()}.apk`
return appPath
}

function checkBuildPresent(buildType: string) {
const appPath = getBuildFolder(buildType)
const appPath = getAppBuildFolder(buildType)
console.debug('appPath', appPath)
return fs.existsSync(appPath)
}

function findBestApkInFolder(dir: string, arc?: string) {

const files = fs.readdirSync(dir)
// todo debug
const singleApkFound = files.find(f => f === 'app-debug.apk')
if (singleApkFound) {
return path.join(dir, 'app-debug.apk')
} else {
if (arc) {
const apkForArc = files.find(f => f.includes(arc))
if (apkForArc) {
return path.join(dir, apkForArc)
} else {
throw Error('Unable to find correct apk in' + dir)
}
} else {
throw Error('Unable to find correct apk in' + dir)
}

}
}

function installApp(device: string, engineDir: string, buildType: string) {
const appPath = getBuildFolder(buildType)
const appDir = getAppBuildFolder(buildType)

execSync(`${getAdbPath()} -s ${device} install -r ${appPath}`)
const cpu = adb.getCPU(getAdbPath(), device)
console.debug('cpus', cpu)

const apkPath = findBestApkInFolder(appDir, cpu || undefined)

execSync(`${getAdbPath()} -s ${device} install -r ${apkPath}`)
}

function launchApp(device: string, packageId: string) {
Expand All @@ -64,22 +89,38 @@ async function getAvailableDevicePort(port = 5552): Promise<number> {
return port
}

export async function runApp(buildType: string, appId: string, port = '8081') {
function getBundleIdentifier(appBuildFolder: string): string {

if (fs.existsSync(path.join(appBuildFolder, 'output-metadata.json'))) {
const id = JSON.parse(fs.readFileSync(path.join(appBuildFolder, 'output-metadata.json'), 'utf-8'))?.applicationId
if (id) {
return id
}
}

// todo improve bundle id identifier
return 'todo'

}

export async function runApp(buildType: string, port = '8081') {

if(!checkBuildPresent(buildType)) {
buildAndroid(buildType as any);
if (!checkBuildPresent(buildType)) {
buildAndroid(buildType)
}

const device = await listAndroidDevices()

const appIdentifier = getBundleIdentifier(getAppBuildFolder(buildType))

if (!device) {
throw new Error('No android devices available')
} else {
if (device.connected) {
tryRunAdbReverse(port, device.deviceId!)

installApp(device.deviceId!, getProjectRootDir(), buildType)
launchApp(device.deviceId!, appId)
launchApp(device.deviceId!, appIdentifier)

} else {
const newEmulatorPort = await getAvailableDevicePort()
Expand All @@ -91,7 +132,7 @@ export async function runApp(buildType: string, appId: string, port = '8081') {
tryRunAdbReverse(port, emulator)

installApp(emulator, getProjectRootDir(), buildType)
launchApp(emulator, appId)
launchApp(emulator, appIdentifier)

}
}
Expand Down
3 changes: 2 additions & 1 deletion src/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ export default class Build extends Command {
}
if (shouldBuildAndroid) {
this.log('Building android')
buildAndroid(buildFlavor as any);
// build release and debug?
buildAndroid(buildFlavor);
}
}
}
2 changes: 1 addition & 1 deletion src/commands/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default class Run extends Command {

if (shouldRunAndroid) {
// todo build and appId
runAndroid('dev', 'com.newrnarctest')
runAndroid(buildFlavor)
}
if (shouldRunIos) {
runIos(buildFlavor)
Expand Down

0 comments on commit a5bf889

Please sign in to comment.