UNPKG

nativescript

Version:

Command-line interface for building NativeScript projects

226 lines • 11 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AndroidApplicationManager = void 0; const os_1 = require("os"); const application_manager_base_1 = require("../application-manager-base"); const constants_1 = require("../../constants"); const helpers_1 = require("../../helpers"); const decorators_1 = require("../../decorators"); const path_1 = require("path"); const _ = require("lodash"); const constants_2 = require("../../../constants"); class AndroidApplicationManager extends application_manager_base_1.ApplicationManagerBase { constructor(adb, identifier, $androidBundleToolService, $fs, $options, $logcatHelper, $androidProcessService, $httpClient, $deviceLogProvider, $errors, $logger, $hooksService) { super($logger, $hooksService, $deviceLogProvider); this.adb = adb; this.identifier = identifier; this.$androidBundleToolService = $androidBundleToolService; this.$fs = $fs; this.$options = $options; this.$logcatHelper = $logcatHelper; this.$androidProcessService = $androidProcessService; this.$httpClient = $httpClient; this.$deviceLogProvider = $deviceLogProvider; this.$errors = $errors; this.PID_CHECK_INTERVAL = 100; this.PID_CHECK_TIMEOUT = 10000; // 10 secs } async getInstalledApplications() { const result = (await this.adb.executeShellCommand(["pm", "list", "packages"])) || ""; const regex = /package:(.+)/; return result .split(os_1.EOL) .map((packageString) => { const match = packageString.match(regex); return match ? match[1] : null; }) .filter((parsedPackage) => parsedPackage !== null); } async installApplication(packageFilePath, appIdentifier, buildData) { if (appIdentifier) { const deviceRootPath = `${constants_1.LiveSyncPaths.ANDROID_TMP_DIR_NAME}/${appIdentifier}`; await this.adb.executeShellCommand(["rm", "-rf", deviceRootPath]); } const { dir, name, ext } = (0, path_1.parse)(packageFilePath); if (ext === constants_2.AAB_EXTENSION_NAME) { const apksOutputPath = (0, path_1.join)(dir, name) + constants_2.APKS_EXTENSION_NAME; if (!this.hasValidApksFile(packageFilePath, apksOutputPath)) { await this.$androidBundleToolService.buildApks({ aabFilePath: packageFilePath, apksOutputPath, signingData: buildData, }); } await this.$androidBundleToolService.installApks({ apksFilePath: apksOutputPath, deviceId: this.identifier, }); } else { return this.adb.executeCommand(["install", "-r", `${packageFilePath}`]); } } uninstallApplication(appIdentifier) { // Need to set the treatErrorsAsWarnings to true because when using tns run command if the application is not installed on the device it will throw error return this.adb.executeShellCommand(["pm", "uninstall", `${appIdentifier}`], { treatErrorsAsWarnings: true }); } async startApplication(appData) { if (appData.waitForDebugger) { await this.adb.executeShellCommand([ `cat /dev/null > ${constants_1.LiveSyncPaths.ANDROID_TMP_DIR_NAME}/${appData.appId}-debugbreak`, ]); } // If the app is debuggable, the Runtime will update the file when its ready for debugging // and we will be able to take decisions and synchronize the debug experience based on the content await this.adb.executeShellCommand([ `cat /dev/null > ${constants_1.LiveSyncPaths.ANDROID_TMP_DIR_NAME}/${appData.appId}-debugger-started`, ]); /* Example "pm dump <app_identifier> | grep -A 1 MAIN" output" android.intent.action.MAIN: 3b2df03 org.nativescript.cliapp/com.tns.NativeScriptActivity filter 50dd82e Action: "android.intent.action.MAIN" Category: "android.intent.category.LAUNCHER" -- intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=org.nativescript.cliapp/com.tns.NativeScriptActivity} realActivity=org.nativescript.cliapp/com.tns.NativeScriptActivity -- Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=org.nativescript.cliapp/com.tns.NativeScriptActivity } frontOfTask=true task=TaskRecord{fe592ac #449 A=org.nativescript.cliapp U=0 StackId=1 sz=1} */ const appIdentifier = appData.appId; const pmDumpOutput = await this.adb.executeShellCommand([ "pm", "dump", appIdentifier, "|", "grep", "-A", "1", "MAIN", ]); const activityMatch = this.getFullyQualifiedActivityRegex(appIdentifier); const match = activityMatch.exec(pmDumpOutput); const possibleIdentifier = match && match[0]; if (possibleIdentifier) { await this.adb.executeShellCommand([ "am", "start", "-n", possibleIdentifier, ]); } else { this.$logger.trace(`Tried starting activity for: ${appIdentifier}, using activity manager but failed.`); await this.adb.executeShellCommand([ "monkey", "-p", appIdentifier, "-c", "android.intent.category.LAUNCHER", "1", ]); } await this.onAppLaunch(appData); } async onAppLaunch(appData) { const appIdentifier = appData.appId; if (!this.$options.justlaunch && !appData.justLaunch) { const deviceIdentifier = this.identifier; const processIdentifier = await this.getAppProcessId(deviceIdentifier, appIdentifier); if (processIdentifier) { this.$deviceLogProvider.setApplicationPidForDevice(deviceIdentifier, processIdentifier); this.$deviceLogProvider.setApplicationIdForDevice(deviceIdentifier, appIdentifier); this.$deviceLogProvider.setProjectDirForDevice(deviceIdentifier, appData.projectDir); await this.$logcatHelper.start({ deviceIdentifier: this.identifier, pid: processIdentifier, appId: appIdentifier, onAppRestarted: () => { // If the app restarts, we update the PID and // restart log helper. this.onAppLaunch(appData); }, }); } else { await this.$logcatHelper.dump(this.identifier); this.$errors.fail(`Unable to find running "${appIdentifier}" application on device "${deviceIdentifier}".`); } } } async getAppProcessId(deviceIdentifier, appIdentifier) { const appIdCheckStartTime = new Date().getTime(); let processIdentifier = ""; let hasTimedOut = false; while (!processIdentifier && !hasTimedOut) { processIdentifier = await this.$androidProcessService.getAppProcessId(deviceIdentifier, appIdentifier); if (!processIdentifier) { this.$logger.trace(`Wasn't able to get pid of the app. Sleeping for "${this.PID_CHECK_INTERVAL}ms".`); await (0, helpers_1.sleep)(this.PID_CHECK_INTERVAL); hasTimedOut = new Date().getTime() - appIdCheckStartTime > this.PID_CHECK_TIMEOUT; } } return processIdentifier; } stopApplication(appData) { this.$logcatHelper.stop(this.identifier); this.$deviceLogProvider.setApplicationPidForDevice(this.identifier, null); this.$deviceLogProvider.setProjectDirForDevice(this.identifier, null); return this.adb.executeShellCommand([ "am", "force-stop", `${appData.appId}`, ]); } getDebuggableApps() { return this.$androidProcessService.getDebuggableApps(this.identifier); } async getDebuggableAppViews(appIdentifiers) { const mappedAppIdentifierPorts = await this.$androidProcessService.getMappedAbstractToTcpPorts(this.identifier, appIdentifiers, constants_1.TARGET_FRAMEWORK_IDENTIFIERS.Cordova), applicationViews = {}; await Promise.all(_.map(mappedAppIdentifierPorts, async (port, appIdentifier) => { applicationViews[appIdentifier] = []; const localAddress = `http://127.0.0.1:${port}/json`; try { if (port) { const apps = (await this.$httpClient.httpRequest(localAddress)) .body; applicationViews[appIdentifier] = JSON.parse(apps); } } catch (err) { this.$logger.trace(`Error while checking ${localAddress}. Error is: ${err.message}`); } })); return applicationViews; } getFullyQualifiedActivityRegex(appIdentifier) { const packageActivitySeparator = "\\/"; const fullJavaClassName = "([a-zA-Z_0-9]*\\.)*[A-Z_$]($[A-Z_$]|[$_\\w_])*"; return new RegExp(`${(0, helpers_1.regExpEscape)(appIdentifier)}${packageActivitySeparator}${fullJavaClassName}`, `m`); } hasValidApksFile(aabFilaPath, apksFilePath) { let isValid = false; if (this.$fs.exists(apksFilePath)) { const lastUpdatedApks = this.$fs.getFsStats(apksFilePath).ctime.getTime(); const lastUpdatedAab = this.$fs.getFsStats(aabFilaPath).ctime.getTime(); isValid = lastUpdatedApks >= lastUpdatedAab; } return isValid; } } exports.AndroidApplicationManager = AndroidApplicationManager; __decorate([ (0, helpers_1.hook)("install") ], AndroidApplicationManager.prototype, "installApplication", null); __decorate([ (0, decorators_1.cache)() ], AndroidApplicationManager.prototype, "getFullyQualifiedActivityRegex", null); //# sourceMappingURL=android-application-manager.js.map