mirror of
https://github.com/apache/cordova-android.git
synced 2026-05-11 00:00:05 +08:00
refactor: unify installation on devices & emulators (#1123)
* refactor: unify installation on devices & emulators This change replaces the almost identical methods `device.install` and `emulator.install` with the generic `target.install`. * fix: use unified installation in platform-centric bins
This commit is contained in:
committed by
GitHub
parent
aa679ea1d6
commit
bb7d733cde
Vendored
-46
@@ -18,11 +18,8 @@
|
||||
*/
|
||||
|
||||
var build = require('./build');
|
||||
var path = require('path');
|
||||
var Adb = require('./Adb');
|
||||
var AndroidManifest = require('./AndroidManifest');
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
var events = require('cordova-common').events;
|
||||
|
||||
/**
|
||||
* Returns a promise for the list of the device ID's found
|
||||
@@ -49,46 +46,3 @@ module.exports.resolveTarget = function (target) {
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Installs a previously built application on the device
|
||||
* and launches it.
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.install = function (target, buildResults) {
|
||||
return Promise.resolve().then(function () {
|
||||
if (target && typeof target === 'object') {
|
||||
return target;
|
||||
}
|
||||
return module.exports.resolveTarget(target);
|
||||
}).then(function (resolvedTarget) {
|
||||
var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
|
||||
var manifest = new AndroidManifest(path.join(__dirname, '../../app/src/main/AndroidManifest.xml'));
|
||||
var pkgName = manifest.getPackageId();
|
||||
var launchName = pkgName + '/.' + manifest.getActivity().getName();
|
||||
events.emit('log', 'Using apk: ' + apk_path);
|
||||
events.emit('log', 'Package name: ' + pkgName);
|
||||
|
||||
return Adb.install(resolvedTarget.target, apk_path, { replace: true }).catch(function (error) {
|
||||
// CB-9557 CB-10157 only uninstall and reinstall app if the one that
|
||||
// is already installed on device was signed w/different certificate
|
||||
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString())) { throw error; }
|
||||
|
||||
events.emit('warn', 'Uninstalling app from device and reinstalling it again because the ' +
|
||||
'installed app already signed with different key');
|
||||
|
||||
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
|
||||
// or the app doesn't installed at all, so no error catching needed.
|
||||
return Adb.uninstall(resolvedTarget.target, pkgName).then(function () {
|
||||
return Adb.install(resolvedTarget.target, apk_path, { replace: true });
|
||||
});
|
||||
}).then(function () {
|
||||
// unlock screen
|
||||
return Adb.shell(resolvedTarget.target, 'input keyevent 82');
|
||||
}).then(function () {
|
||||
return Adb.start(resolvedTarget.target, launchName);
|
||||
}).then(function () {
|
||||
events.emit('log', 'LAUNCH SUCCESS');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
-88
@@ -20,11 +20,9 @@
|
||||
const execa = require('execa');
|
||||
const fs = require('fs-extra');
|
||||
var android_versions = require('android-versions');
|
||||
var retry = require('./retry');
|
||||
var build = require('./build');
|
||||
var path = require('path');
|
||||
var Adb = require('./Adb');
|
||||
var AndroidManifest = require('./AndroidManifest');
|
||||
var events = require('cordova-common').events;
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
var android_sdk = require('./android_sdk');
|
||||
@@ -33,11 +31,7 @@ var which = require('which');
|
||||
|
||||
// constants
|
||||
const ONE_SECOND = 1000; // in milliseconds
|
||||
const ONE_MINUTE = 60 * ONE_SECOND; // in milliseconds
|
||||
const INSTALL_COMMAND_TIMEOUT = 5 * ONE_MINUTE; // in milliseconds
|
||||
const NUM_INSTALL_RETRIES = 3;
|
||||
const CHECK_BOOTED_INTERVAL = 3 * ONE_SECOND; // in milliseconds
|
||||
const EXEC_KILL_SIGNAL = 'SIGKILL';
|
||||
|
||||
function forgivingWhichSync (cmd) {
|
||||
const whichResult = which.sync(cmd, { nothrow: true });
|
||||
@@ -373,85 +367,3 @@ module.exports.resolveTarget = function (target) {
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Installs a previously built application on the emulator and launches it.
|
||||
* If no target is specified, then it picks one.
|
||||
* If no started emulators are found, error out.
|
||||
* Returns a promise.
|
||||
*/
|
||||
module.exports.install = function (givenTarget, buildResults) {
|
||||
var target;
|
||||
// We need to find the proper path to the Android Manifest
|
||||
const manifestPath = path.join(__dirname, '..', '..', 'app', 'src', 'main', 'AndroidManifest.xml');
|
||||
const manifest = new AndroidManifest(manifestPath);
|
||||
const pkgName = manifest.getPackageId();
|
||||
|
||||
// resolve the target emulator
|
||||
return Promise.resolve().then(function () {
|
||||
if (givenTarget && typeof givenTarget === 'object') {
|
||||
return givenTarget;
|
||||
} else {
|
||||
return module.exports.resolveTarget(givenTarget);
|
||||
}
|
||||
|
||||
// set the resolved target
|
||||
}).then(function (resolvedTarget) {
|
||||
target = resolvedTarget;
|
||||
|
||||
// install the app
|
||||
}).then(function () {
|
||||
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
|
||||
// or the app doesn't installed at all, so no error catching needed.
|
||||
return Promise.resolve().then(function () {
|
||||
var apk_path = build.findBestApkForArchitecture(buildResults, target.arch);
|
||||
|
||||
events.emit('log', 'Using apk: ' + apk_path);
|
||||
events.emit('log', 'Package name: ' + pkgName);
|
||||
events.emit('verbose', 'Installing app on emulator...');
|
||||
|
||||
// A special function to call adb install in specific environment w/ specific options.
|
||||
// Introduced as a part of fix for http://issues.apache.org/jira/browse/CB-9119
|
||||
// to workaround sporadic emulator hangs
|
||||
function adbInstallWithOptions (...args) {
|
||||
return Adb.install(...args, {
|
||||
replace: true,
|
||||
execOptions: {
|
||||
timeout: INSTALL_COMMAND_TIMEOUT, // in milliseconds
|
||||
killSignal: EXEC_KILL_SIGNAL
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function installPromise () {
|
||||
return adbInstallWithOptions(target.target, apk_path).catch(function (error) {
|
||||
// CB-9557 CB-10157 only uninstall and reinstall app if the one that
|
||||
// is already installed on device was signed w/different certificate
|
||||
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString())) { throw error; }
|
||||
|
||||
events.emit('warn', 'Uninstalling app from device and reinstalling it because the ' +
|
||||
'currently installed app was signed with different key');
|
||||
|
||||
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
|
||||
// or the app doesn't installed at all, so no error catching needed.
|
||||
return Adb.uninstall(target.target, pkgName).then(function () {
|
||||
return adbInstallWithOptions(target.target, apk_path);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return retry.retryPromise(NUM_INSTALL_RETRIES, installPromise).then(function (output) {
|
||||
events.emit('log', 'INSTALL SUCCESS');
|
||||
});
|
||||
});
|
||||
// unlock screen
|
||||
}).then(function () {
|
||||
events.emit('verbose', 'Unlocking screen...');
|
||||
return Adb.shell(target.target, 'input keyevent 82');
|
||||
}).then(function () {
|
||||
Adb.start(target.target, pkgName + '/.' + manifest.getActivity().getName());
|
||||
// report success or failure
|
||||
}).then(function (output) {
|
||||
events.emit('log', 'LAUNCH SUCCESS');
|
||||
});
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
const { install } = require('./target');
|
||||
var device = require('./device');
|
||||
var args = process.argv;
|
||||
|
||||
@@ -26,17 +27,13 @@ if (args.length > 2) {
|
||||
var install_target;
|
||||
if (args[2].substring(0, 9) === '--target=') {
|
||||
install_target = args[2].substring(9, args[2].length);
|
||||
device.install(install_target).catch(function (err) {
|
||||
console.error('ERROR: ' + err);
|
||||
process.exit(2);
|
||||
});
|
||||
} else {
|
||||
console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
|
||||
process.exit(2);
|
||||
}
|
||||
} else {
|
||||
device.install().catch(function (err) {
|
||||
console.error('ERROR: ' + err);
|
||||
process.exit(2);
|
||||
});
|
||||
}
|
||||
|
||||
device.resolveTarget(install_target).then(install).catch(err => {
|
||||
console.error('ERROR: ' + err);
|
||||
process.exit(2);
|
||||
});
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
under the License.
|
||||
*/
|
||||
|
||||
const { install } = require('./target');
|
||||
var emulator = require('./emulator');
|
||||
var args = process.argv;
|
||||
|
||||
@@ -32,7 +33,7 @@ if (args.length > 2) {
|
||||
}
|
||||
}
|
||||
|
||||
emulator.install(install_target).catch(function (err) {
|
||||
emulator.resolveTarget(install_target).then(install).catch(err => {
|
||||
console.error('ERROR: ' + err);
|
||||
process.exit(2);
|
||||
});
|
||||
|
||||
Vendored
+4
-5
@@ -20,6 +20,7 @@
|
||||
var path = require('path');
|
||||
var emulator = require('./emulator');
|
||||
var device = require('./device');
|
||||
const target = require('./target');
|
||||
var PackageType = require('./PackageType');
|
||||
const { CordovaError, events } = require('cordova-common');
|
||||
|
||||
@@ -110,14 +111,12 @@ module.exports.run = function (runOptions) {
|
||||
}
|
||||
|
||||
resolve(self._builder.fetchBuildResults(buildOptions.buildType, buildOptions.arch));
|
||||
}).then(function (buildResults) {
|
||||
}).then(async function (buildResults) {
|
||||
if (resolvedTarget && resolvedTarget.isEmulator) {
|
||||
return emulator.wait_for_boot(resolvedTarget.target).then(function () {
|
||||
return emulator.install(resolvedTarget, buildResults);
|
||||
});
|
||||
await emulator.wait_for_boot(resolvedTarget.id);
|
||||
}
|
||||
|
||||
return device.install(resolvedTarget, buildResults);
|
||||
return target.install(resolvedTarget, buildResults);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Vendored
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const Adb = require('./Adb');
|
||||
const build = require('./build');
|
||||
const AndroidManifest = require('./AndroidManifest');
|
||||
const { retryPromise } = require('./retry');
|
||||
const { events } = require('cordova-common');
|
||||
|
||||
const INSTALL_COMMAND_TIMEOUT = 5 * 60 * 1000;
|
||||
const NUM_INSTALL_RETRIES = 3;
|
||||
const EXEC_KILL_SIGNAL = 'SIGKILL';
|
||||
|
||||
exports.install = async function ({ target, arch, isEmulator }, buildResults) {
|
||||
const apk_path = build.findBestApkForArchitecture(buildResults, arch);
|
||||
const manifest = new AndroidManifest(path.join(__dirname, '../../app/src/main/AndroidManifest.xml'));
|
||||
const pkgName = manifest.getPackageId();
|
||||
const launchName = pkgName + '/.' + manifest.getActivity().getName();
|
||||
|
||||
events.emit('log', 'Using apk: ' + apk_path);
|
||||
events.emit('log', 'Package name: ' + pkgName);
|
||||
events.emit('verbose', `Installing app on target ${target}`);
|
||||
|
||||
async function doInstall (execOptions = {}) {
|
||||
try {
|
||||
await Adb.install(target, apk_path, { replace: true, execOptions });
|
||||
} catch (error) {
|
||||
// CB-9557 CB-10157 only uninstall and reinstall app if the one that
|
||||
// is already installed on device was signed w/different certificate
|
||||
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString())) throw error;
|
||||
|
||||
events.emit('warn', 'Uninstalling app from device and reinstalling it again because the ' +
|
||||
'installed app already signed with different key');
|
||||
|
||||
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
|
||||
// or the app doesn't installed at all, so no error catching needed.
|
||||
await Adb.uninstall(target, pkgName);
|
||||
await Adb.install(target, apk_path, { replace: true });
|
||||
}
|
||||
}
|
||||
|
||||
if (isEmulator) {
|
||||
// Work around sporadic emulator hangs: http://issues.apache.org/jira/browse/CB-9119
|
||||
await retryPromise(NUM_INSTALL_RETRIES, () => doInstall({
|
||||
timeout: INSTALL_COMMAND_TIMEOUT,
|
||||
killSignal: EXEC_KILL_SIGNAL
|
||||
}));
|
||||
} else {
|
||||
await doInstall();
|
||||
}
|
||||
events.emit('log', 'INSTALL SUCCESS');
|
||||
|
||||
events.emit('verbose', 'Unlocking screen...');
|
||||
await Adb.shell(target, 'input keyevent 82');
|
||||
|
||||
await Adb.start(target, launchName);
|
||||
events.emit('log', 'LAUNCH SUCCESS');
|
||||
};
|
||||
Reference in New Issue
Block a user