mobile-cli-lib
不同 CLI 使用的通用库
npm i --save mobile-cli-lib

mobile-cli-lib

提供了一种轻松处理设备的方法。包含 CLI 的常用基础设施 - 主要为 AppBuilder 和 NativeScript。

安装

最新版本:0.22.0

发布日期:2016年12月15日

系统要求

在安装 mobile-cli-lib 之前,请确保您的系统满足以下要求。

Windows 系统

最低软件要求

  • Windows 7 或更高版本
  • .NET 4.0 或更高版本
  • Node.js
    • (Windows 7 系统):Node.js 0.10.26 或更高版本的稳定官方发布版(除 0.10.34 之外)
      一个已知的 问题 阻止了 mobile-cli-lib 与 Node.js 0.10.34 正确工作。
    • (Windows 8 及更高版本系统):Node.js 0.12.0 或更高版本的稳定官方发布版
      Inquirer.js 中的一个 已知问题 阻止了在 Windows 8 或更高版本的系统上的 Node.js 0.10.x 的 cmd 命令行外壳中正确地执行交互式提示。

针对 iOS 在设备上部署的附加软件要求

  • iTunes(最新官方版本)
  • Node.js

Node.js 和 iTunes 的位数必须匹配。

针对 Android 在设备上部署的附加软件要求

  • 系统需要为识别连接的 Android 设备而安装的设备驱动程序
  • 在原生仿真器中进行测试
    • JDK 8 或更高版本
    • Android SDK 19 或更高版本
    • (可选) Genymotion

针对 Windows Phone 在设备上部署的附加软件要求

在本版 mobile-cli-lib 中,您无法从命令行部署和 LiveSync 连接到的 Windows Phone 设备。

OS X 系统

最低软件要求

  • OS X Mavericks
  • Node.js 0.10.26 或更高版本的稳定官方发布版(除 0.10.34 之外)
    一个 已知问题 阻止了 mobile-cli-lib 与 Node.js 0.10.34 正确工作。
  • Mono 3.12 或更高版本

针对 iOS 在设备上部署的附加软件要求

  • iTunes(最新官方版本)
  • 在原生仿真器中进行测试
    • Xcode 5 或更高版本

针对 Android 在设备上部署的附加软件要求

  • 系统需要为识别连接的 Android 设备而安装的设备驱动程序
  • 在原生仿真器中进行测试
    • JDK 8 或更高版本
    • Android SDK 19 或更高版本
    • (可选) Genymotion

针对 Windows Phone 在设备上部署的附加软件要求

在本版 mobile-cli-lib 中,您无法从命令行部署和 LiveSync 连接到的 Windows Phone 设备。

Linux 系统

最低软件要求

  • Ubuntu 14.04 LTS
    mobile-cli-lib 已在 Ubuntu 14.04 LTS 上进行测试和验证,以确保其运行。您可能能够在其他 Linux 发行版上运行 mobile-cli-lib

  • Node.js 0.10.26 或更高版本的稳定官方发布版(除 0.10.34 之外)
    一个 已知问题 阻止了 mobile-cli-lib 与 Node.js 0.10.34 正确工作。

    提示:您可以通过以下说明 在此 安装您的系统上的 Node.js。

  • 互联网浏览器(最新官方版本)

  • (64 位系统) ia32/i386 架构的运行库

    • 在终端中运行以下命令。

      sudo apt-get install lib32z1 lib32ncurses5 lib32bz2-1.0 libstdc++6:i386

针对 iOS 在设备上部署的附加软件要求

在本版 mobile-cli-lib 中,您无法从命令行部署和 LiveSync 连接到的 iOS 设备。您需要手动使用 iTunes 部署应用程序包。

针对 Android 在设备上部署的附加软件要求

  • 系统需要为识别连接的 Android 设备而安装的设备驱动程序
  • G++ 编译器
    • 在终端中运行 sudo apt-get install g++
  • 在原生仿真器中进行测试
    • JDK 8 或更高版本
    • Android SDK 19 或更高版本
    • (可选) Genymotion

针对 Windows Phone 在设备上部署的附加软件要求

在本版 mobile-cli-lib 中,您无法从命令行部署和 LiveSync 连接到的 Windows Phone 设备。

安装 mobile-cli-lib

应将 mobile-cli-lib 添加到项目的 package.json 文件中作为依赖项。

用法

为了使用 mobile-cli-lib,只需在您的 package.json 中添加对其的引用即可

dependencies: {
"mobile-cli-lib": "0.4.0"
}

之后,在 package.json 所在的目录中执行 npm install 命令。这个命令将把所有依赖安装到 node_modules 目录中。现在您可以在项目中使用 mobile-cli-lib

var common = require("mobile-cli-lib");
common.fs.getFileSize("D:\\Work\\t.txt")
.then(function (result) {
console.log("File size is: " + result);
return result;
}, function (err) {
console.log("Error happened:");
console.log(err);
});

示例应用

您可以在这里找到一个示例应用。只需下载 zip 文件,然后在项目目录中执行 npm install。之后,您可以在终端中执行 node index.js。如果您有文件 D:\Work\t.txt,应用将显示其大小。如果没有这样的文件,应用将显示错误。您可以在 index.js 中更改文件名。

公共 API

本节包含有关每个公共方法的信息。

与设备相关的公共 API,暴露 IDeviceInfo 数据,包含以下信息

/**
* Describes available information for a device.
*/
interface IDeviceInfo {
/**
* Unique identifier of the device.
*/
identifier: string;

/**
* The name of the device.
* For Android this is the value of device's 'ro.product.name' property.
* For iOS this is the value of device'
s 'DeviceName' property.
*/
displayName: string;

/**
* Device model.
* For Android this is the value of device's 'ro.product.model' property.
* For iOS this is the value of device'
s 'ProductType' property.
*/
model: string;

/**
* Version of the OS.
* For Android this is the value of device's 'ro.build.version.release' property.
* For iOS this is the value of device'
s 'ProductVersion' property.
*/
version: string;

/**
* Vendor of the device.
* For Android this is the value of device's 'ro.product.brand' property.
* For iOS the value is always "Apple".
*/
vendor: string;

/**
* Device'
s platform.
* Can be Android or iOS.
*/
platform: string;

/**
* Status of device describing if you can work with this device or there's communication error.
* Can be Connected or Unreachable.
*/
status: string;

/**
* Additional information for errors that prevents working with this device.
* It will be null when status is Connected.
*/
errorHelp: string;

/**
* Defines if the device is tablet or not.
* For Android the value will be true when device'
s 'ro.build.characteristics' property contains "tablet" word or when the 'ro.build.version.release' is 3.x
* For iOS the value will be true when device's 'ProductType' property contains "ipad" word.
*/
isTablet: boolean;

/**
* Optional property describing the color of the device.
* Available for iOS only - the value of device'
s 'DeviceColor' property.
*/
color?: string;

/**
* Optional property describing the architecture of the device
* Available for iOS only - can be "armv7" or "arm64"
*/
activeArchitecture?: string;
}

模块 companionAppsService

稳定性 2 - 稳定

companionAppsService 提供对伴随应用标识符的访问。

  • getAllCompanionAppIdentifiers:返回一个 JSON 对象中的所有伴随应用标识符,其中顶级键是框架(cordova 和 nativescript),内部键是平台(android、ios、wp8)。示例用法
var companionAppIdentifiers = require("mobile-cli-lib").companionAppsService.getAllCompanionAppIdentifiers();

结果对象类似于

{
'cordova': {
'android': 'android.cordova.companion.app.identifier',
'ios': 'ios.cordova.companion.app.identifier',
'wp8': 'wp8.cordova.companion.app.identifier'
},
'nativescript': {
'android': 'android.nativescript.companion.app.identifier',
'ios': 'ios.nativescript.companion.app.identifier',
'wp8': null
}
}
  • getCompanionAppIdentifier(framework: string, platform: string): string - 返回指定框架和平台的伴随应用标识符。示例用法
var companionAppIdentifiers = require("mobile-cli-lib").companionAppsService.getCompanionAppIdentifier("cordova", "android");

模块 deviceEmitter

稳定性 2 - 稳定

deviceEmitter 模块用于发出与系统连接的设备相关的事件。您可以使用 deviceEmitter 为以下事件添加处理程序

  • deviceFound - 当新设备连接到系统时触发。回调函数将接收一个参数 - deviceInfoData。示例用法
require("mobile-cli-lib").deviceEmitter.on("deviceFound",  function(deviceInfoData) {
console.log("Found device with identifier: " + deviceInfoData.identifier);
});
  • deviceLost - 当设备从系统中断开连接时触发。回调函数将接收一个参数 - deviceInfoData。示例用法
require("mobile-cli-lib").deviceEmitter.on("deviceLost",  function(deviceInfoData) {
console.log("Detached device with identifier: " + deviceInfoData.identifier);
});
  • deviceLogData - 当连接的设备报告任何信息时触发。这是 Android 设备的 adb logcat 输出。对于 iOS,这是 iOS SysLog。此事件对报告数据的任何设备都会触发。回调函数有两个参数 - deviceIdentifierreportedData

    示例用法
require("mobile-cli-lib").deviceEmitter.on("deviceLogData",  function(identifier, reportedData) {
console.log("Device " + identifier + " reports: " + reportedData);
});
  • applicationInstalled - 当应用安装到设备上时触发。回调有两个参数 - deviceIdentifierapplicationIdentifier

    示例用法
require("mobile-cli-lib").deviceEmitter.on("applicationInstalled",  function(identifier, applicationIdentifier) {
console.log("Application " + applicationIdentifier + " has been installed on device with id: " + identifier);
});
  • applicationUninstalled - 当应用从设备上移除时触发。回调有两个参数 - deviceIdentifierapplicationIdentifier

    示例用法
require("mobile-cli-lib").deviceEmitter.on("applicationUninstalled",  function(identifier, applicationIdentifier) {
console.log("Application " + applicationIdentifier + " has been uninstalled from device with id: " + identifier);
});
  • debuggableAppFound - 当设备上的应用可进行调试时触发。回调有一个参数 - applicationInfo

    示例用法
require("mobile-cli-lib").deviceEmitter.on("debuggableAppFound",  function(applicationInfo) {
console.log("Application " + applicationInfo.appIdentifier + " is available for debugging on device with id: " + applicationInfo.deviceIdentifier);
});

对于 applicationInfo 的示例结果将是

{
"deviceIdentifier": "4df18f307d8a8f1b",
"appIdentifier": "com.telerik.Fitness",
"framework": "NativeScript",
"title": "NativeScript Application"
}
  • debuggableAppLost - 当设备上的应用不再可进行调试时触发。回调有一个参数 - applicationInfo

    示例用法
require("mobile-cli-lib").deviceEmitter.on("debuggableAppLost",  function(applicationInfo) {
console.log("Application " + applicationInfo.appIdentifier + " is not available for debugging anymore on device with id: " + applicationInfo.deviceIdentifier);
});

对于 applicationInfo 的示例结果将是

{
"deviceIdentifier": "4df18f307d8a8f1b",
"appIdentifier": "com.telerik.Fitness",
"framework": "NativeScript",
"title": "NativeScript Application"
}
  • debuggableViewFound - 当找到新的可调试 WebView 时触发。回调有三个参数 - deviceIdentifierappIdentifierwebViewInfo

示例用法

require("mobile-cli-lib")
.deviceEmitter.on("debuggableViewFound", function(deviceIdentifier, appIdentifier, debuggableViewInfo) {
console.log("On device " + deviceIdentifier + " the application " + appIdentifier + " now has new WebView: " + debuggableViewInfo);
});

对于 debuggableViewInfo 的示例结果将是

{
"description": "",
"devtoolsFrontendUrl": "http://chrome-devtools-frontend.appspot.com/serve_rev/@211d45a5b74b06d12bb016f3c4d54095faf2646f/inspector.html?ws=127.0.0.1:53213/devtools/page/4050",
"id": "4050",
"title": "New tab",
"type": "page",
"url": "chrome-native://newtab/",
"webSocketDebuggerUrl": "ws://127.0.0.1:53213/devtools/page/4050"
}
  • debuggableViewLost - 当可调试 WebView 失去时触发。回调有三个参数 - deviceIdentifierappIdentifierwebViewInfo

示例用法

require("mobile-cli-lib")
.deviceEmitter.on("debuggableViewLost", function(deviceIdentifier, appIdentifier, debuggableViewInfo) {
console.log("On device " + deviceIdentifier + " the application " + appIdentifier + " now cannot debug WebView: " + debuggableViewInfo);
});

对于 debuggableViewInfo 的示例结果将是

{
"description": "",
"devtoolsFrontendUrl": "http://chrome-devtools-frontend.appspot.com/serve_rev/@211d45a5b74b06d12bb016f3c4d54095faf2646f/inspector.html?ws=127.0.0.1:53213/devtools/page/4050",
"id": "4050",
"title": "New tab",
"type": "page",
"url": "chrome-native://newtab/",
"webSocketDebuggerUrl": "ws://127.0.0.1:53213/devtools/page/4050"
}
  • debuggableViewChanged - 当可调试 WebView 的属性发生变化时触发,例如它的标题。回调有三个参数 - deviceIdentifierappIdentifierwebViewInfo

示例用法

require("mobile-cli-lib")
.deviceEmitter.on("debuggableViewChanged", function(deviceIdentifier, appIdentifier, debuggableViewInfo) {
console.log("On device " + deviceIdentifier + " the application " + appIdentifier + " has changes in WebView: " + debuggableViewInfo);
});

对于 debuggableViewInfo 的示例结果将是

{
"description": "",
"devtoolsFrontendUrl": "http://chrome-devtools-frontend.appspot.com/serve_rev/@211d45a5b74b06d12bb016f3c4d54095faf2646f/inspector.html?ws=127.0.0.1:53213/devtools/page/4050",
"id": "4050",
"title": "New tab 2",
"type": "page",
"url": "chrome-native://newtab/",
"webSocketDebuggerUrl": "ws://127.0.0.1:53213/devtools/page/4050"
}
  • companionAppInstalled - 当应用从设备上移除时触发。回调有两个参数 - deviceIdentifierframwork

    示例用法
require("mobile-cli-lib").deviceEmitter.on("companionAppInstalled",  function(identifier, framwework) {
console.log("Companion app for " + framework + " has been installed on device with id: " + identifier);
});
  • companionAppUninstalled - 当应用程序从设备中删除时触发。回调有两个参数 - deviceIdentifierframwork

    示例用法
require("mobile-cli-lib").deviceEmitter.on("companionAppUninstalled",  function(identifier, framwework) {
console.log("Companion app for " + framework + " has been uninstalled from device with id: " + identifier);
});

模块 devicesService

稳定性:2 - 稳定

此模块允许与设备交互。您可以获得已连接设备的列表或在特定设备上部署。

  • getDevices() - 此函数返回所有连接设备的数组。对于每个设备,以下信息会被提供:示例用法
var devices = require("mobile-cli-lib").devicesService.getDevices();
devices.forEach(function(device) {
console.log("Device " + device.identifier + " is connected.");
});
  • deployOnDevices(deviceIdentifiers: string[], packageFile: string, packageName: string, framework: string) - 将指定的包部署到指定的设备。返回一个 Promise 数组。如果文件无法部署在设备上或没有具有该标识符的设备,则每个 Promise 将被拒绝。该函数接受三个参数
    • deviceIdentifiers - 需要部署应用程序的设备唯一标识符数组。
    • packageFile - 指定包的路径(.apk.ipa);
    • packageName - 包的标识符。这对应于 .abproject 中的 appId。
    • framework - 项目的框架。有效的值是 CordovaNativeScript

示例用法

Promise.all(require("mobile-cli-lib")
.devicesService
.deployOnDevices(["129604ab96a4d0053023b4bf5b288cf34a9ed5fa", "153544fa45f4a5646543b5bf1b221fe31a8fa6bc"], "./app.ipa", "com.telerik.testApp", "Cordova"))
.then(function(data) {
console.log(data);
}, function(err) {
console.log(err);
});
  • setLogLevel(logLevel: string, deviceIdentifier?: string) - 将设备(s)的日志级别设置为 INFOFULL。该方法有两个参数,只有第一个是必需的。当仅传递 logLevel 时,其值用于所有当前连接的设备以及未来将连接的设备。默认日志级别为 INFO。例如,当有两个设备连接且按以下方式调用此方法时
require("mobile-cli-lib").devicesService.setLogLevel("FULL");

设备报告的所有内容都将触发 deviceEmitter.deviceLogData 事件。当新设备连接时,它报告的所有信息也将发送。当传递 deviceIdentifier 时,日志级别的值仅适用于该设备。例如,当所有设备报告所有日志(FULL)级别时,您可以调用

require("mobile-cli-lib").devicesService.setLogLevel("INFO", "129604ab96a4d0053023b4bf5b288cf34a9ed5fa");

这将仅将设备的日志级别设置为 INFO,设备标识符为 129604ab96a4d0053023b4bf5b288cf34a9ed5fa

  • isAppInstalledOnDevices(deviceIdentifiers: string[], appIdentifier: string, framework: string): Promise<IAppInstalledInfo>[] - 检查指定应用程序是否在每个指定的设备上安装,并支持 LiveSync。每个设备的返回类型为 IAppInstalledInfo
/**
* Describes if LiveSync is supported for specific device and application.
*/
interface IAppInstalledInfo extends ILiveSyncSupportedInfo {
/**
* Unique identifier of the device.
*/
deviceIdentifier: string;

/**
* Application identifier.
*/
appIdentifier: string;

/**
* Defines if application is installed on device.
*/
isInstalled: boolean;

/**
* Result, indicating is livesync supported for specified device and specified application.
* `true` in case livesync is supported and false otherwise.
*/
isLiveSyncSupported: boolean;
}

注意:此方法将尝试在每个设备上启动应用程序,以了解是否支持 LiveSync。示例用法

Promise.all(require("mobile-cli-lib")
.devicesService
.isAppInstalledOnDevices(devicesFound, "com.telerik.myApp", "cordova"))
.then(function(data) {
console.log(data);
}, function(err) {
console.log(err);
});

示例结果将是

[{
"deviceIdentifier": "deviceId1",
"appIdentifier": "appId",
"isInstalled": true,
"isLiveSyncSupported": true
}, {
"deviceIdentifier": "deviceId2",
"appIdentifier": "appId",
"isInstalled": false,
"isLiveSyncSupported": false
}]
  • isCompanionAppInstalledOnDevices(deviceIdentifiers: string[], framework: string): Promise<IAppInstalledInfo>[] - 检查伴随应用程序是否在每个指定的设备上安装,并支持 LiveSync。每个设备的返回类型为 IAppInstalledInfo(请参阅上面的完整接口描述)。示例用法
Promise.all(require("mobile-cli-lib")
.devicesService
.isCompanionAppInstalledOnDevices(devicesFound, "cordova"))
.then(function(data) {
console.log(data);
}, function(err) {
console.log(err);
});

示例结果将是

[{
"deviceIdentifier": "deviceId1",
"appIdentifier": "com.telerik.AppBuilder",
"isInstalled": true,
"isLiveSyncSupported": true
}, {
"deviceIdentifier": "deviceId2",
"appIdentifier": "com.telerik.AppBuilder",
"isInstalled": false,
"isLiveSyncSupported": false
}]
  • mapAbstractToTcpPort(deviceIdentifier: string, appIdentifier: string, framework: string): Promise<string> - 此函数将设备上 Web 视图的抽象端口转发到主机的可用 TCP 端口,并返回 TCP 端口。

示例用法

require("mobile-cli-lib").devicesService.mapAbstractToTcpPort("4df18f307d8a8f1b", "com.telerik.test", "Cordova")
.then(function(port) {
console.log(port);
}, function(err) {
console.log(err);
});
  • getDebuggableApps(deviceIdentifiers: string[]): Promise<IDeviceApplicationInformation[]>[] - 此函数检查设备Identifiers 参数中的每个设备的 proc/net/unix 文件,并返回应用程序。
/**
* Describes basic information about application on device.
*/
interface IDeviceApplicationInformation {
/**
* The device identifier.
*/
deviceIdentifier: string;

/**
* The application identifier.
*/
appIdentifier: string;

/**
* The framework of the project (Cordova or NativeScript).
*/
framework: string;
}

示例用法

Promise.all(require("mobile-cli-lib").devicesService.getDebuggableApps(["4df18f307d8a8f1b", "JJY5KBTW75TCHQUK"]))
.then(function(data) {
data.forEach(function(apps) {
console.log(apps);
});
}, function(err) {
console.log(err);
});

示例结果将是

[[{
"deviceIdentifier": "4df18f307d8a8f1b",
"appIdentifier": "com.telerik.Fitness",
"framework": "NativeScript"
}, {
"deviceIdentifier": "4df18f307d8a8f1b",
"appIdentifier": "com.telerik.livesynctest",
"framework": "Cordova"
}], [{
"deviceIdentifier": "JJY5KBTW75TCHQUK",
"appIdentifier": "com.telerik.PhotoAlbum",
"framework": "NativeScript"
}]]
  • getDebuggableApps(deviceIdentifiers: string[]): Promise<IDeviceApplicationInformation[]>[] - 此函数检查设备Identifiers 参数中的每个设备的 proc/net/unix 文件,并返回应用程序。
/**
* Describes basic information about application on device.
*/
interface IDeviceApplicationInformation {
/**
* The device identifier.
*/
deviceIdentifier: string;

/**
* The application identifier.
*/
appIdentifier: string;

/**
* The framework of the project (Cordova or NativeScript).
*/
framework: string;
}

示例用法

Promise.all(require("mobile-cli-lib").devicesService.getDebuggableApps(["4df18f307d8a8f1b", "JJY5KBTW75TCHQUK"]))
.then(function(data) {
data.forEach(function(apps) {
console.log(apps);
});
}, function(err) {
console.log(err);
});

示例结果将是

[[{
"deviceIdentifier": "4df18f307d8a8f1b",
"appIdentifier": "com.telerik.Fitness",
"framework": "NativeScript"
}, {
"deviceIdentifier": "4df18f307d8a8f1b",
"appIdentifier": "com.telerik.livesynctest",
"framework": "Cordova"
}], [{
"deviceIdentifier": "JJY5KBTW75TCHQUK",
"appIdentifier": "com.telerik.PhotoAlbum",
"framework": "NativeScript"
}]]
  • getDebugableViews(device: string, app: string): Promise<IDebugWebViewInfo[]> - 此函数指定设备上的 WebViews,可以调试指定应用程序。

注意:此方法仅适用于基于 Cordova 的应用程序。不要传递 NativeScript 应用程序的应用程序。

/**
* Describes information for WebView that can be debugged.
*/
interface IDebugWebViewInfo {
/**
* Short description of the view.
*/
description: string;

/**
* Url to the devtools.
* @example http://chrome-devtools-frontend.appspot.com/serve_rev/@211d45a5b74b06d12bb016f3c4d54095faf2646f/inspector.html?ws=127.0.0.1:53213/devtools/page/4024
*/
devtoolsFrontendUrl: string;

/**
* Unique identifier of the web view. Could be number or GUID.
* @example 4027
*/
id: string;

/**
* Title of the WebView.
* @example https://bit.ly/12345V is not available
*/
title: string;

/**
* Type of the WebView.
* @example page
*/
type: string;

/**
* URL loaded in the view.
* @example https://bit.ly/12345V
*/
url: string;

/**
* Debugger URL.
* @example ws://127.0.0.1:53213/devtools/page/4027
*/
webSocketDebuggerUrl: string;
}

示例用法

require("mobile-cli-lib")
.devicesService
.getDebuggableViews("4df18f307d8a8f1b", "com.telerik.cordovaApp")
.then(function(data) {
console.log(data);
}, function(err) {
console.log(err);
});

示例结果将是

[{
"description": "",
"devtoolsFrontendUrl": "http://chrome-devtools-frontend.appspot.com/serve_rev/@211d45a5b74b06d12bb016f3c4d54095faf2646f/inspector.html?ws=127.0.0.1:53213/devtools/page/4050",
"id": "4050",
"title": "New tab",
"type": "page",
"url": "chrome-native://newtab/",
"webSocketDebuggerUrl": "ws://127.0.0.1:53213/devtools/page/4050"
},

{
"description": "",
"devtoolsFrontendUrl": "http://chrome-devtools-frontend.appspot.com/serve_rev/@211d45a5b74b06d12bb016f3c4d54095faf2646f/inspector.html?ws=127.0.0.1:53213/devtools/page/4032",
"id": "4032",
"title": "New tab",
"type": "page",
"url": "chrome-native://newtab/",
"webSocketDebuggerUrl": "ws://127.0.0.1:53213/devtools/page/4032"
}
]

模块 iDeviceService

稳定性:3 - 稳定

本模块允许在不同设备上运行LiveSync应用程序。

以下类型被使用

/**
* Describes the result of a single livesync operation started by Proton.
*/
interface ILiveSyncOperationResult {
/**
* Defines if the operation is successful (set to true) or not (value is false).
*/
isResolved: boolean;

/**
* Error when livesync operation fails. If `isResolved` is true, error will be undefined.
*/
error?: Error;
}

/**
* Describes result of all LiveSync operations per device.
*/
interface IDeviceLiveSyncResult {
/**
* Identifier of the device.
*/
deviceIdentifier: string;

/**
* Result of LiveSync operation for application.
*/
liveSyncToApp?: ILiveSyncOperationResult;

/**
* Result of LiveSync operation to companion app.
*/
liveSyncToCompanion?: ILiveSyncOperationResult;
}
  • livesync(devicesInfo: IDeviceLiveSyncInfo[], projectDir: string, filePaths?: string[]): Promise<IDeviceLiveSyncResult>[] - 在指定设备上进行LiveSync更改。如果未指定filePathes,则整个项目目录将进行同步。devicesInfo数组描述了每个设备的livesync操作。每个对象应使用以下属性进行描述
/**
* Describes device's LiveSync information.
*/
interface IDeviceLiveSyncInfo {
/**
* Unique identifier of the device.
*/
deviceIdentifier: string;

/**
* Defines if changes have to be synced to installed application.
*/
syncToApp: boolean;

/**
* Defines if changes have to be synced to companion app.
*/
syncToCompanion: boolean;
}

示例用法

var deviceInfos = [{"deviceIdentifier": "129604ab96a4d0053023b4bf5b288cf34a9ed5fa", "syncToApp": true, "syncToCompanion": false},
{"deviceIdentifier": "153544fa45f4a5646543b5bf1b221fe31a8fa6bc", "syncToApp": true, "syncToCompanion": false}];
// Full Sync - the whole project dir will be synced
Promise.all(require("mobile-cli-lib").liveSyncService.livesync(deviceInfos, projectDir))
.then(function(result) {
console.log("Finished with full sync, result is: ", result);
}).catch(function(err) {
console.log("Error while livesyncing: ", err);
});

// Or use livesync only for some files:
var filesToSync = [path.join(projectDir,"app","components", "homeView", "homeView.xml"),
path.join(projectDir,"app","components", "addressView", "addressView.xml")]
Promise.all(require("mobile-cli-lib").liveSyncService.livesync(deviceInfos, projectDir, filesToSync))
.then(function(result) {
console.log("Finished with partial sync, result is: ", result);
}).catch(function(err) {
console.log("Error while livesyncing: ", err);
});
  • deleteFiles(devicesInfo: IDeviceLiveSyncInfo[], projectDir: string, filePaths: string[]): Promise<IDeviceLiveSyncResult>[] - 从设备的livesync目录中删除指定的文件。devicesInfo数组描述了每个设备的livesync操作。有关更多信息,请参阅上面的livesync方法。

示例用法

var deviceInfos = [{"deviceIdentifier": "129604ab96a4d0053023b4bf5b288cf34a9ed5fa", "syncToApp": true, "syncToCompanion": false},
{"deviceIdentifier": "153544fa45f4a5646543b5bf1b221fe31a8fa6bc", "syncToApp": true, "syncToCompanion": false}];

var filesToSync = [path.join(projectDir,"app","components", "homeView", "homeView.xml"),
path.join(projectDir,"app","components", "addressView", "addressView.xml")]
Promise.all(require("mobile-cli-lib").liveSyncService.deleteFiles(deviceInfos, projectDir, filesToSync))
.then(function(result) {
console.log("Finished with deleting files, result is: ", result);
}).catch(function(err) {
console.log("Error while deleting files: ", err);
});

模块npmService

稳定性:3 - 稳定

此模块用于从npm安装或卸载包。

以下类型被使用

/**
* Describes information for single npm dependency that has to be installed.
*/
interface INpmDependency {
/**
* Name of the dependency.
*/
name: string;

/**
* @optional The version of the dependency that has to be installed.
*/
version?: string;

/**
* Defines if @types/<name> should be installed as well.
*/
installTypes: boolean;
}

/**
* Describes the result of npm install command.
*/
interface INpmInstallResult {
/**
* The result of installing a single dependency.
*/
result?: INpmInstallDependencyResult,

/**
* The error that occurred during the operation.
*/
error?: Error;
}
  • install(projectDir: string, dependencyToInstall?: INpmDependency): Promise<INpmInstallResult> - 从package.json安装所有内容或指定的依赖项。如果有关于要安装的依赖项的信息,该方法将检查它,并只安装此依赖项以及可能的@types。

示例用法

// Install all dependencies from package.json.
require("mobile-cli-lib").npmService.install("D:\\test\\project")
.then(function(result) {
console.log("The npm result is: ", result);
}).catch(function(err) {
console.log("Error while installing packages from npm: ", err);
});

示例结果将是

{}
// Install specific dependency from npm.
var dependency = {
name: "lodash",
version: "4.15.0",
installTypes: true
};

require("mobile-cli-lib").npmService.install("D:\\test\\project", dependency)
.then(function(result) {
console.log("The npm result is: ", result);
}).catch(function(err) {
console.log("Error while installing packages from npm: ", err);
});

示例结果将是

{
"result": {
"isInstalled": true,
"isTypesInstalled": true
}
}
  • uninstall(projectDir: string, dependency: string): Promise - 卸载依赖项及其@types/devDependency。该方法将从package.json和node_modules目录中删除它们。。注意:此方法将删除它们。

示例用法

require("mobile-cli-lib").npmService.uninstall("D:\\test\\project", "lodash")
.then(function() {
console.log("The dependency is uninstalled.");
}).catch(function(err) {
console.log("Error while uninstalling packages from npm: ", err);
});

模块typeScriptService

稳定性:3 - 稳定

此模块用于转换TypeScript文件。

以下类型被使用

interface ITypeScriptCompilerOptions {
/**
* Specify the codepage to use when opening source files.
*/
codePage?: number;

/**
* Generates corresponding .d.ts file.
*/
declaration?: boolean;

/**
* Specifies the location where debugger should locate map files instead of generated locations.
*/
mapRoot?: string;

/**
* Specify module code generation: 'commonjs' or 'amd'.
*/
module?: string;

/**
* Warn on expressions and declarations with an implied 'any' type.
*/
noImplicitAny?: boolean;

/**
* Concatenate and emit output to single file.
*/
outFile?: string;

/**
* Redirect output structure to the directory.
*/
outDir?: string;

/**
* Do not emit comments to output.
*/
removeComments?: boolean;

/**
* Generates corresponding .map file.
*/
sourceMap?: boolean;

/**
* Specifies the location where debugger should locate TypeScript files instead of source locations.
*/
sourceRoot?: string;

/**
* Specify ECMAScript target version: 'ES3' (default), or 'ES5'.
*/
target?: string;

/**
* Do not emit outputs if any errors were reported.
*/
noEmitOnError?: boolean;

[key: string]: any;
}

/**
* Describes the options for transpiling TypeScript files.
*/
interface ITypeScriptTranspileOptions {
/**
* Describes the options in tsconfig.json file.
*/
compilerOptions?: ITypeScriptCompilerOptions;

/**
* The default options which will be used if there is no tsconfig.json file.
*/
defaultCompilerOptions?: ITypeScriptCompilerOptions;

/**
* Path to the default .d.ts files.
*/
pathToDefaultDefinitionFiles?: string;
}
  • transpile(projectDir: string, typeScriptFiles?: string[], definitionFiles?: string[], options?: ITypeScriptTranspileOptions): Promise<string> - 转换指定的文件或项目目录中的所有文件。如果未指定options,则方法将搜索tsconfig.json文件并从中获取它们。如果没有tsconfig.json文件,则使用默认选项。如果没有typeScriptFiles,则将转换projectDir中的所有文件。返回的结果是TypeScript编译器的输出。

示例用法

// Transpile only 2 files.
var projectDir = "D:\\test\\project";
var filesToTranspile = [path.join(projectDir,"app","components", "homeView", "homeView.ts"),
path.join(projectDir,"app","components", "addressView", "addressView.ts")];

require("mobile-cli-lib").typeScriptService.transpile(projectDir, filesToTranspile)
.then(function(result) {
console.log("TypeScript compiler result: ", result);
}).catch(function(err) {
console.log("Error while transpiling files: ", err);
});

如果没有错误,则样本结果将是

""

有错误时的样本结果将是

"app/components/homeView/homeView.ts(19,1): error TS2304: Cannot find name 'a'.
app/components/homeView/homeView.ts(20,1): error TS2304: Cannot find name 'b'."
// Transpile all files in project.
require("mobile-cli-lib").typeScriptService.transpile("D:\\test\\project")
.then(function(result) {
console.log("TypeScript compiler result: ", result);
}).catch(function(err) {
console.log("Error while transpiling files: ", err);
});

技术细节

注入器

类似于AngularJSmobile-cli-lib使用$injector检索对象实例、实例化类型和加载模块。每个模块都必须在$injector中注册,因此当另一个模块依赖于它时,$injector将创建依赖项的新实例或重用已创建的一个。

如何添加新模块

  • 添加一个新文件,使用kebab-case(spinal-case)命名。例如,当您要添加的类名为DeviceService时,将文件命名为device-service.ts是良好实践。

  • 在文件中添加您的类。类名应使用Pascal case

class DeviceService {
}

注意:顶部的引用路径必须指向项目的根目录,其中.d.ts文件由grunt创建。

  • 使用所有其他模块将使用以获取DeviceService实例的名称在注入器中注册类。名称应使用Camel case
class DeviceService {
}
$injector.register("deviceService", DeviceService);
  • 在实现中添加您需要的任何方法
class DeviceService {
public listDevices(): void {
// implementation is here
}
}
$injector.register("deviceService", DeviceService);
  • 如果您的类依赖于在$injector中注册的其他模块,您可以通过将它们添加为构造函数的参数来访问它们
class DeviceService {
constructor(private $fs: IFileSystem) { }
}
$injector.register("deviceService", DeviceService);

注意:如果您不放置访问修饰符(privateprotectedpublic),您只能在构造函数中使用依赖模块。

注意:模块的名称必须与在$injector中注册的名称完全相同,在本例中是fs模块。前缀美元符号$是必需的。现在您可以通过使用this.$fs.<method>来使用fs方法。

  • 最后一步是将您的模块添加到bootstrap.ts
$injector.require("deviceService", "./device-service");

此行告诉$injectormobile-cli-lib根目录下查找位于文件device-service中的名为"deviceService"的模块。

注意:模块的名称必须与在 $injector.register 调用中使用的一致。$injector.require 不会加载文件。当有人请求“deviceService”模块时,将由 $injector 加载。

如何使方法公开

为了暴露公共API,我们在引导过程中使用了TypeScript装饰器和一些“魔法”。当你想从类A中公开方法B时,你必须执行以下操作:

  • bootstrap.ts 中,确保在要求文件时使用 $injectorrequirePublic 方法。
$injector.requirePublic("deviceService", "./device-service")
  • 在你想公开的方法上添加导出装饰器:@decorators.exported('deviceService'),其中装饰器是从项目根目录导入的:import decorators = require("./decorators");

重要:exported 装饰器需要一个参数,该参数必须是传递给 requirePublic 方法的第一个参数。这是将要公开的模块的名称。

执行这两个步骤后,你可以开始使用你的公开方法。

var common = require("mobile-cli-lib");
common.deviceService.listDevices() /* NOTE: here we are not using the class name DeviceService, but the module name - deviceService */
.then(function (a) {
console.log("After promise had returned.");
return a;
})
.catch(function (err) {
console.log("Error happened:");
console.log(err);
});

生成公共API背后的场景

injectorrequirePublic 方法进行了一些“魔法”,以支持延迟加载、正确的依赖解析,并且只公开一些方法,而不是公共库的全部功能。当你要求 mobile-cli-lib 模块时,你接收 $injector 的公共Api - 它是“导出的”。requirePublic 方法为传递的每个模块定义了getter,例如,当你这样说时:

	$injector.requirePublic("deviceService", "./device-service")

在publicApi中添加了一个新属性deviceService,并为它添加了一个getter。当你尝试访问这个模块时,require("mobile-cli-lib").deviceService.listDevices(),getter被调用。它通过解析提供的文件(./device-service)来解析模块,这就是装饰器执行的时候。对于每个装饰的方法,在$injector.publicApi.__modules__中创建一个新条目。这不是你装饰的方法 - 它是一个全新的方法,返回一个Promise。新方法将在publicApi中使用,而原始实现将在代码的其他所有地方使用。这个Promise方法将调用原始方法(在单独的Fiber中),并用方法的结果解析Promise。

问题

缺失依赖项

必须添加一些我们的模块:staticConfig、config、analyticsService等。

注入器测试

为yok和register装饰器添加更多测试。