Cordova
阅读本指南后,您将了解
- 什么是 Cordova,以及 Meteor 如何与之集成以从单个代码库构建移动应用
- 如何在本地机器上设置移动开发环境
- 如何在移动设备或模拟器/仿真器上运行和调试您的应用
- 热代码推送如何允许您更新移动应用的代码,而无需在设备上重新安装应用或向商店提交新版本
- 如何使用 Cordova 插件利用原生设备功能
- 如何从您的应用访问本地文件和远程资源
- 您可以做些什么来为您的应用创建良好的移动用户体验
- 如何配置您的应用以使用您自己的应用图标、启动画面并设置其他首选项
- 如何构建您的项目并将您的移动应用提交到商店
Meteor Cordova 集成
Meteor 与 Cordova 集成,Cordova 是一个著名的 Apache 开源项目,用于从您用于创建常规 Web 应用的相同代码库构建移动应用。使用 Meteor 中的 Cordova 集成,您可以使用几个命令获取您现有的应用并在 iOS 或 Android 设备上运行它。
Cordova 应用是一个使用 HTML、CSS 和 JavaScript 编写的 Web 应用,但它运行在嵌入在原生应用中的 Web 视图 中,而不是在独立的移动浏览器中。将您的 Web 应用打包为 Cordova 应用的一个重要好处是,所有资产都与应用捆绑在一起。这确保了您的应用加载速度比运行在远程服务器上的 Web 应用更快,这对于使用缓慢移动网络的用户来说可能会有很大区别。Meteor 中的 Cordova 集成的另一个功能是支持 热代码推送,它允许您更新用户设备上的应用,而无需经过通常的应用商店审查流程。
Cordova 还通过 插件架构 打开了对某些原生设备功能的访问。插件允许您使用 Web 应用通常无法使用的功能,例如访问设备摄像头或本地文件系统,与条形码或 NFC 阅读器交互等。
因为 Cordova 应用是一个 Web 应用,这意味着您使用标准 Web 元素创建用户界面,而不是依赖于特定于平台的原生 UI 组件。创建良好的移动用户体验本身就是一门艺术,但幸运的是,各种框架和库的可用性对此有所帮助。
PhoneGap 是什么?
您可能听说过 PhoneGap,并想知道它与 Cordova 的关系。PhoneGap 是 Adobe 自 2011 年以来使用的产品名称,当时他们收购了一家名为 Nitobi 的公司,该公司是现在 Cordova 项目的最初创建者。当 Adobe 在 2012 年将代码捐赠给 Apache 以确保更开放的治理模型时,该开源项目被重新命名为 Cordova。PhoneGap 现在是 Cordova 的发行版之一,与 Ionic、Telerik、Monaca 或 Intel XDK 等其他发行版处于同等地位。这些发行版主要在工具和与云服务的集成方面有所不同,但它们共享底层平台和插件。Meteor 也可以被认为是 Cordova 的一个发行版。
它是如何工作的?
使用 Meteor,无需自行安装 Cordova 或直接使用 cordova
命令。Cordova 项目创建作为 Meteor 运行和构建命令的一部分发生,并且该项目本身被视为构建工件(存储在应用目录中的 .meteor/local/cordova-build
中),可以随时删除和重新创建。Meteor 不让您修改 Cordova 的 config.xml
文件,而是读取应用目录根目录中的 mobile-config.js
文件,并使用其中指定的设置配置生成的项目。
Cordova 应用不会通过网络加载 Web 内容,而是依赖于本地存储的 HTML、CSS、JavaScript 代码和其他资产。虽然 Cordova 默认使用 file://
URL 加载应用,但 Meteor 在设备上包含了一个集成的文件服务机制,以支持捆绑初始资产以及通过 热代码推送 增量更新您的应用。这意味着您的应用将从 https://127.0.0.1:<port>
提供服务,这也具有 Web 视图将其视为 安全来源 并且不会阻止任何敏感功能(它们越来越倾向于阻止 file://
URL)的优点。
上面提到的端口将根据存储在应用程序中 .meteor/.id
文件中的应用程序 ID 生成。如果您需要在同一设备上使用相同的源代码运行多个应用,则应为每个运行的应用指定不同的端口,方法是在运行 Cordova run
和 build
命令时使用 --cordova-server-port <port>
选项。否则,您将无法在 iOS 上同时运行多个应用。此问题的一个常见症状是 XCode 控制台中出现错误 Failed binding IPv4 listening socket: Address already in use (48)
。
您的应用将从哪个端口提供服务?
虽然 Meteor 在 Android 上使用内置的请求拦截机制,但在 iOS 上支持
WKWebView
需要运行一个真正的嵌入式 Web 服务器。这意味着本地 Web 服务器需要一个端口来绑定,而且我们不能简单地使用固定端口,因为这可能会导致在同一设备上运行多个 Meteor Cordova 应用时发生冲突。最简单的解决方案似乎是使用随机端口,但这有一个严重的缺点:如果每次运行应用时端口都发生变化,则依赖于来源的 Web 功能(如缓存、localStorage、IndexedDB)不会在运行之间持久化,并且您也无法指定稳定的 OAuth 重定向 URL。因此,我们现在从预定的范围 (12000-13000) 中选择一个端口,该端口根据appId
计算得出,appId
是每个 Meteor 项目的一部分的唯一标识符。这确保了相同的应用将始终使用相同的端口,但希望尽可能避免应用之间的冲突。(仍然存在所选端口可能正在使用的理论可能性。目前,在这种情况下,启动本地服务器将失败。)
运行时环境
Cordova 应用在 Web 视图中运行。Web 视图基本上是一个没有浏览器 UI 的浏览器。浏览器引擎在其底层实现和支持的 Web 标准方面有所不同。因此,您的应用运行在哪个 Web 视图上会对应用的性能以及您可以使用哪些功能产生重大影响。(如果您想知道哪些功能在哪些浏览器和版本上受支持,caniuse.com 是一个很好的资源。)
iOS
iOS 上的浏览器是 Safari,它基于开源 WebKit 项目,但启用新功能的速度往往有点慢。因为它们使用相同的底层框架,所以 Web 视图可用的功能与您正在运行的 iOS 版本上 Safari 支持的功能相匹配。
Meteor 在 iOS 8 和 iOS 9 上默认使用 WKWebView。WKWebView 是 iOS 8 中引入的现代 WebKit API 的一部分,它取代了从一开始就在 iOS 中的 UIWebView。其主要优点是它在单独的进程中运行,从而实现更高的 JavaScript 性能(在某些基准测试中提高了 3-4 倍!),因为它可以利用即时编译(UIWebView 在与您的应用相同的进程中运行,出于安全原因无法这样做)。
您可能知道,iOS 8 上的 WKWebView 不允许从本地文件系统加载文件。这对标准 Cordova 应用来说是个问题,因为它们使用
file://
URL 加载应用。但是,由于 Meteor 集成从localhost
提供资产,因此 WKWebView 在 iOS 8 和 iOS 9 上都能正常工作。
Android
Android 5.0 及更高版本附带了一个基于 Chromium 的 Web 视图,称为 Android 系统 Web 视图,它可以通过 Play 商店自动更新。这意味着 Web 视图的更新可以定期发生,并且独立于操作系统更新。
添加 Cordova 平台
每个 Meteor 项目都针对一组平台。可以使用 meteor add-platform
将平台添加到 Meteor 项目中。
meteor add-platform ios
将 iOS 平台添加到项目中。meteor add-platform android
将 Android 平台添加到项目中。meteor remove-platform ios android
将从项目中删除 iOS 和 Android 平台。meteor list-platforms
列出您的项目所针对的平台。
如果您的本地机器尚未满足构建移动平台应用的 先决条件,则会打印一条包含缺少要求列表的错误消息(但平台仍然会添加)。您必须确保满足这些要求,然后才能从您的机器构建和运行移动应用。
安装先决条件
为了构建和运行移动应用,您需要在本地机器上安装一些先决条件。
iOS
为了构建和运行 iOS 应用,您需要一台安装了 Apple Xcode 开发者工具的 Mac。我们建议安装最新版本,但您还应该查看 Meteor 历史记录 以了解任何特定版本依赖项。注意:要使用 Xcode 10.2+ 构建,您的 webapp 包必须为 v1.7.4 或更高版本。
从 App Store 安装 Xcode
运行meteor add-platform ios
会弹出一个对话框,询问您是否要安装“命令行开发者工具”。请不要在这里选择“安装”,因为构建和运行 iOS 应用需要完整的 Xcode 安装。相反,选择“获取 Xcode”将打开 Xcode 的 Mac App Store 页面,您可以在那里点击安装。(或者,您可以打开 Mac App Store 并搜索“Xcode”以访问同一页面。)
接受许可协议
下载和安装完成后,您需要接受许可协议。如果您第一次启动 Xcode,将弹出一个对话框,您可以在其中阅读许可协议并接受它。之后可以直接关闭 Xcode。
一个快捷方式是从命令行运行sudo xcodebuild -license accept
。(您仍然需要阅读并理解Xcode 和 Apple SDK 协议)。
从Cordova iOS 4.3.0开始,您可能还需要运行
sudo gem install cocoapods
来解决与PhoneGap 推送插件的依赖关系。
启用 Xcode 命令行工具
从 Mac App Store 安装 Xcode 后,仍然需要在终端环境中启用这些工具。可以通过在命令提示符下运行以下命令来实现。
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
Android
对于 Mac OSX Intel 和 Linux 架构,请按照以下说明操作。Mac M1 用户,请继续滚动到下一节。注意:如果您想针对 Android 的 SDK 31,则需要使用 Java 11 或更高版本,并且还安装了最新的 cmdline-tools。
为了构建和运行 Android 应用,您需要
安装 Java 开发工具包 (JDK)
安装 Android SDK 并下载所需的工具、平台和其他组件(最简单的方法是安装 Android Studio)
设置
ANDROID_HOME
并将工具目录添加到您的PATH
可选:创建一个 Android 虚拟设备以在模拟器上运行应用
如果找不到 Gradle:尝试使用包管理器,例如Homebrew、
apt-get
或yum
来安装系统范围的独立版本gradle
# On Mac OSX: brew install gradle # On Debian/Ubuntu: sudo apt-get install gradle
有关安装 Gradle 的更多信息,请参阅此处。
安装 Java 开发工具包 (JDK)
在 Linux 上,您可能希望使用发行版的包管理器来安装 JDK;在 Ubuntu 上,您甚至可以使用Ubuntu Make同时安装 Android Studio 和所有依赖项。
- 打开Oracle Java 网站,然后选择 Java 平台 (JDK)
- 选中复选框以接受许可协议,然后选择适合您平台的正确下载
- 下载完成后,启动安装程序并完成安装步骤
安装 Android Studio
获得工作 Android 开发环境的最简单方法是安装Android Studio,它在首次启动时提供一个设置向导,该向导会为您安装 Android SDK,并下载一组默认的工具、平台和其他组件,您需要这些组件才能开始开发。
有关要遵循的确切步骤的更多详细信息,请参阅Android Studio 安装说明。
如果您更喜欢独立安装,则无需使用 Android Studio。只需确保安装了最新版本的Android 命令行工具。
确保选择正确版本的Android Studio SDK 工具
- Meteor 1.4.3.1 及更高版本:Android SDK 工具 v.25.2.x(mac、linux、windows)或 v.26.0.0 或更高版本
- 由于重大更改,v.25.3.0将无法使用。有关更多信息,请参阅问题 #8464。
- Meteor 1.4.2.x 或更早版本:Android SDK 工具 v.23(mac、linux、windows)
要安装旧版本的 SDK 工具
- 从以上链接下载您需要的版本
- 替换
~/Library/Android/sdk/
中的tools/
文件夹
注意:如果您使用的是旧版本的 Meteor,您可能还需要安装旧版本的 Android SDK,例如使用 Android Studio 附带的 Android SDK Manager。
使用 Ubuntu Make
如果您运行的是 Ubuntu,则安装 Java 开发工具包和 Android Studio 的一种方法是使用Ubuntu Make,这是一个为您设置开发环境和依赖项的命令行工具。
如果您使用的是 Ubuntu 14.04 LTS,则必须首先添加 Ubuntu Make ppa
sudo add-apt-repository ppa:ubuntu-desktop/ubuntu-make
sudo apt-get update
然后,您可以安装 Ubuntu Make 本身
sudo apt-get install ubuntu-make
最后,您可以使用 Ubuntu Make 安装 Android Studio 和所有依赖项
umake android
设置`ANDROID_HOME`并将工具目录添加到您的`PATH`
Cordova 会自动检测在各种标准位置安装的 Android SDK,但是为了从终端使用诸如android
或adb
之类的工具,您需要对环境进行一些更改。
Mac
- 将
ANDROID_HOME
环境变量设置为 Android SDK 的位置。如果您使用过 Android Studio 设置向导,则默认情况下它应该安装在~/Library/Android/sdk
中。 - 将
$ANDROID_HOME/tools
和$ANDROID_HOME/platform-tools
添加到您的PATH
您可以通过将这些行添加到您的~/.bash_profile
文件(或您 shell 环境的等效文件,如~/.zshrc
)中来实现。
# Android
export ANDROID_HOME="$HOME/Library/Android/sdk"
export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
然后,您需要重新加载.bash_profile
(通过执行source ~/.bash_profile
)或打开一个新的终端会话以应用新环境。
可选:创建 Android 虚拟设备 (AVD) 以在模拟器上运行应用
当前的 Android 模拟器往往比较慢且可能不稳定,因此我们建议您在物理设备上运行您的应用。
但是,如果您确实想在模拟器上运行,则必须使用AVD Manager创建一个 Android 虚拟设备 (AVD)。确保使用您正在使用的Cordova Android版本的支持的 API 级别配置 AVD。
Mac M1
为了使 Android 在 m1 机器上运行- 从此处安装 Java 开发工具包 (JDK) 8
- 从官方网站安装 Android SDK 并下载所需的工具、平台和其他组件(最简单的方法是安装 Android Studio),并针对 ARM 架构。
- 在 Android Studio 上创建一个虚拟设备,添加任何型号(例如 Pixel 4)以及 Android 11(API 30)
- 在您的
.bashrc
或.zshrc
文件中设置以下 PATHexport ANDROID_HOME=$HOME/Library/Android/sdk export ANDROID_SDK_ROOT=${ANDROID_HOME} export PATH=${PATH}:${ANDROID_HOME}/emulator export PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
请记住使用
source ~/.zshrc
或source ~/.bashrc
重新加载您的配置
- 使用
brew install gradle
安装gradle
在设备上开发
在开发过程中,Meteor 构建工具与 Cordova 集成,以在物理设备或 iOS 模拟器/Android 模拟器上运行您的应用。除了像往常一样启动开发服务器和 MongoDB 实例之外,meteor run
还接受参数以在所有一个或多个移动目标上运行应用
ios
:在 iOS 模拟器上运行应用这将在默认的模拟 iOS 设备上运行您的应用。您可以打开 Xcode 以安装并选择另一个模拟设备。
ios-device
:打开 Xcode,您可以在其中在连接的 iOS 设备或模拟器上运行应用android
:在 Android 模拟器上运行应用当前的 Android 模拟器往往比较慢且可能不稳定。我们建议您在物理设备上运行或使用其他模拟器,例如Genymotion。
android-device
:在连接的 Android 设备上运行应用
您可以指定多个目标,例如meteor run ios android-device
将分别在 iOS 模拟器和 Android 设备上运行应用。
连接到服务器
Meteor 应用应该能够连接到服务器以加载数据并启用热代码推送,当您更改其文件时,热代码推送会自动更新正在运行的应用。在开发过程中,这意味着设备和运行meteor
的计算机必须位于同一 WiFi 网络中,并且网络配置不应阻止设备访问服务器。您可能需要更改防火墙或路由器设置以允许这样做(无客户端隔离)。
meteor run
将尝试自动检测运行该命令的计算机的本地 IP 地址。如果失败,或者如果您希望您的移动应用连接到其他服务器,则可以使用--mobile-server
选项指定地址。
在 iOS 上
注意:如果您以前从未开发过 iOS 应用,或者尚未将连接的设备用于开发,则在 Xcode 解决代码签名问题时可能会出现一系列对话框和警告。它也可能会提示您授权访问密钥链中的密钥。有关更多信息,请参阅Apple 的说明。您还需要加入Apple 开发者计划才能在 Apple iOS App Store 上部署您的应用。
- 确保设备通过 USB 线缆连接到您的计算机。
- 将设备连接到允许与服务器通信的 WiFi 网络。
- 运行
meteor run ios-device
以在 Xcode 中打开您的项目。 - 在项目导航器中,从方案工具栏菜单中选择您的设备:
- 点击运行按钮:
- Xcode 构建应用,将其安装在设备上并启动它。
在 Android 上
- 确保设备通过 USB 线缆连接到您的计算机。
- 将设备连接到允许与服务器通信的 WiFi 网络。
- 确保您的设备已设置为开发如这里所述。
- 您可能还需要在设备上的
允许 USB 调试?
提示上点击“允许”。 - 运行
meteor run android-device
以构建应用,将其安装在设备上并启动它。
要检查您的设备是否已正确连接和设置,您可以运行
adb devices
以获取设备列表。
日志记录和调试
一个完整的移动应用包含许多活动部件,这使得诊断问题变得困难。日志记录对于跟踪应用中发生的事情至关重要,它可能会显示您可能错过的警告和错误。更强大的功能是远程调试,它能够从 Safari(适用于 iOS)或 Chrome(适用于 Android)中的调试界面与远程设备上运行的移动应用进行交互。
不同类型的日志
在 Meteor Cordova 应用中,您会遇到三种类型的日志
- 服务器端日志 - Meteor 构建系统打印的消息,以及来自服务器端代码的
console
日志记录调用的结果。 - 客户端 Web 日志 - 来自 Web 视图的警告和错误,以及来自客户端代码的
console
日志记录调用的结果。 - 客户端原生日志 - 来自系统组件和 Cordova 插件的消息。这还包括用于 热代码推送 的 Meteor 插件提供的更详细的日志记录。
使用 meteor run
时,服务器端日志将像往常一样打印到终端。此外,在 Android 设备或模拟器上运行时,会将一部分日志打印到同一终端(这些日志还包括从客户端代码进行的 console
日志记录调用)。
在 iOS 上运行时,终端不会显示客户端日志,但 Xcode 会像往常一样在 调试控制台 中显示原生日志。您可以将 cordova-plugin-console 添加到您的项目中,以便将 console
日志记录调用输出到原生日志(Android 默认情况下会这样做),但这样做不建议,因为它会对性能产生重大影响,而远程调试则可以提供更友好和更完整的控制台输出。
尽管在终端中拥有客户端日志可能很有用,但在大多数情况下,远程调试是一个更好的选择。这使您可以使用内置于 Safari(适用于 iOS 应用)或 Chrome(适用于 Android 应用)中的调试工具来调查在远程设备或模拟器/仿真器上运行的应用。在这里,您不仅可以查看日志,还可以与正在运行的 JavaScript 代码和 DOM 交互,监控网络访问等。
使用 Safari 调试 iOS
要在 Safari 中使用远程调试,您首先需要启用开发者菜单。转到Safari > 首选项,并确保选中“在菜单栏中显示开发菜单”
您还需要在 iOS 设备上启用 Web 检查器。转到设置 > Safari > 高级并启用“Web 检查器”
在您的设备上启动应用,并通过选择开发 > <您的设备> > <您的应用>/localhost打开远程调试器。
由于您只能在应用启动后连接到它,因此有时会错过启动警告和错误。您可以在 Web 检查器控制台中调用
location.reload()
以重新加载正在运行的应用,这次连接了远程调试器。
您可以在 Safari 开发者指南 中找到有关远程调试的更多信息。
使用 Chrome 调试 Android
请参阅 本文,了解如何使用 Chrome DevTools 远程调试 Android 应用。
由于您只能在应用启动后连接到它,因此有时会错过启动警告和错误。您可以在 DevTools 控制台中调用
location.reload()
以重新加载正在运行的应用,这次连接了远程调试器。除非您通过
meteor build --debug
创建调试版本,否则meteor build
生成的 .apk 文件无法进行远程调试。
移动端的热代码推送
在开发过程中,Meteor 构建工具 会检测任何相关的文件更改,重新编译必要的文件,并通知所有连接的客户端有新版本可用。然后,客户端可以自动重新加载应用,切换到新版本的代码。这称为热代码推送。
Meteor 支持浏览器和移动客户端的热代码推送,但移动端的流程略有不同。在浏览器中,重新加载应用会重新向服务器请求资源,服务器将响应最新版本。但是,由于 Cordova 应用依赖于本地存储的资源,因此移动端的热代码推送是一个两步过程
- 使用原生下载机制从服务器下载更新的资源,并将其存储在设备上
- 页面重新加载,Web 视图从本地 Web 服务器重新请求资源
这一个重要的好处是,虽然通过移动连接下载可能很慢,但这在后台完成,并且我们只会在所有资源都下载到设备后才尝试重新加载应用。
更新的下载是增量进行的,因此我们只下载实际更改的资源(基于内容哈希)。此外,如果由于网络故障或应用在完成下载前关闭而无法一次下载所有更改的资源,我们将在应用下次启动或网络连接恢复时重新使用已完成下载的资源。
如果热代码推送在您的应用中无法可靠地工作,并且本节内容无济于事,请参阅我们的 热代码推送问题诊断指南。
生产环境
热代码推送极大地改善了开发体验,但在移动端,它也是生产应用中非常有用的功能,因为它允许您快速将更新推送到设备,而无需用户通过应用商店更新应用,也无需经历可能漫长的审查流程来获得更新批准。
但是,务必注意,热代码推送只能用于更新构成 Web 应用的 HTML、CSS、JavaScript 代码和其他资源。原生代码的更改仍需要您 向应用商店提交新版本的应用。
为了避免将依赖于已更改原生代码的 JavaScript 代码推送到客户端的情况,我们从 Cordova 平台和插件版本计算兼容性版本哈希,并且仅在完全匹配时才将新版本下载到设备。这意味着对插件列表的任何更改,或更新到包含新平台版本的 Meteor 版本,都将阻止热代码推送至现有移动客户端,直到应用从应用商店更新。
需要牢记的另一件事是,您的服务器端代码应准备处理来自旧版客户端的请求,这些客户端可能尚未更新。例如,当您更改数据模式或发布函数时,您可能需要考虑这将如何影响向后兼容性。
控制兼容性版本
兼容性版本可以在 meteor run [ios/android]
期间在 ROOT_URL/__cordova/manifest.json
中提供的 JSON 文件的 cordovaCompatibilityVersions
属性中找到。
如果您希望热代码推送能够到达没有来自应用商店的最新版本原生代码的旧版应用,则可能需要覆盖兼容性版本。假设您正在开发一个 iOS 应用,您有插件 [email protected]
,并且您的应用具有上面所示的兼容性版本 3ed5b9318b2916b595f7721759ead4d708dfbd46
。如果您要更新到 cordova-plugin-camera
的 2.4.1
版本,您的服务器将生成一个新的兼容性版本,并且用户的应用将停止接收热代码推送。但是,您可以告诉您的服务器使用旧的兼容性版本
METEOR_CORDOVA_COMPAT_VERSION_IOS=3ed5b9318b2916b595f7721759ead4d708dfbd46 meteor run ios-device
# or
METEOR_CORDOVA_COMPAT_VERSION_IOS=3ed5b9318b2916b595f7721759ead4d708dfbd46 meteor build ../build --server=127.0.0.1:3000
现在,用户的应用将继续接收热代码推送。但是,他们必须等到从应用商店更新后才能获得 Cordova 插件的新版本。在这种情况下,这没问题,因为我们只更新了一个补丁版本,因此 cordova-plugin-camera
API 没有更改。但是,如果您添加了一个新插件,例如 cordova-plugin-gyroscope
,并更改了您的 Javascript 以调用 navigator.gyroscope.getCurrent()
,那么当旧版应用获取新的 JS 代码时,它们将抛出错误:Uncaught TypeError: Cannot read property 'getCurrent' of undefined
。
另一种选择是使用 METEOR_CORDOVA_COMPAT_VERSION_EXCLUDE
环境变量。如果您这样做
meteor add cordova:[email protected]
meteor add cordova:[email protected]
METEOR_CORDOVA_COMPAT_VERSION_EXCLUDE='cordova-plugin-camera,cordova-plugin-gyroscope' meteor run ios-device
您的兼容性版本将不会更改。
METEOR_CORDOVA_COMPAT_VERSION_*
环境变量必须在您通过 run
、build
或 deploy
**构建**应用时存在。
在应用内访问兼容性版本
manifest.json
的 version
属性(仅反映 JS 包的版本)可以通过 JS 中的 __meteor_runtime_config__.autoupdateVersionCordova
访问。
可以使用 cordova-plugin-file
从清单文件中读取 cordovaCompatibilityVersions.*
属性。
配置服务器
如前所述,移动应用需要能够 连接到服务器 以支持热代码推送。在生产环境中,您需要使用 --server
选项在 构建应用 时指定要连接的服务器。指定的服务器地址用于在 __meteor_runtime_config__
中设置 ROOT_URL
,该变量定义为应用包中生成的 index.html
的一部分。
此外,您需要使用正确的连接地址配置服务器。如果您使用 meteor deploy
部署到 Galaxy,则会自动执行此操作,但在部署到您自己的服务器时,您需要确保在其中定义 ROOT_URL
环境变量。(对于 Meteor Up,您可以在 mup.json
中配置此变量。)
需要这样做是因为通过热代码推送交付的更新会将最初捆绑的 index.html
替换为新生成的 index.html
。如果服务器上的 ROOT_URL
未设置,则默认为 localhost:3000
,这将使应用无法连接到服务器,无论是用于数据加载还是接收进一步的热代码推送。在 Meteor 1.3 中,我们通过阻止更改 ROOT_URL
为 localhost
的更新来防止这种情况,但这会导致热代码推送被禁用,直到您正确配置 ROOT_URL
。
从错误版本中恢复
将新的 JavaScript 代码热代码推送至设备可能会意外推送包含错误的代码,这可能会导致用户遇到应用崩溃(最糟糕的情况是“白屏死机”),甚至可能禁用热代码推送(因为连接到服务器的代码可能不再运行)。
为了避免这种情况,我们尝试检测错误版本,并在发生这种情况时回滚到上次已知的良好版本。检测的工作方式是我们期望所有 Meteor.startup()
回调在设定的时间段内完成。如果这没有发生,我们会认为该版本有故障,并将回滚更新。除非服务器上的版本在此期间已更新,否则服务器将尝试再次热代码推送有故障的版本。因此,我们在设备上将有故障的版本列入黑名单,以便我们知道不要重试。
默认情况下,启动超时设置为 20 秒。如果您的应用需要更多时间启动(或少得多),您可以使用 App.setPreference
将 WebAppStartupTimeout
设置为另一个值。
// The timeout is specified in milliseconds!
App.setPreference('WebAppStartupTimeout', 30000);
使用 Cordova 插件的原生功能
Cordova 带有一个插件架构,可以访问 Web 应用通常无法访问的功能。插件是可以安装的附加组件,包含 JavaScript 和原生代码,允许它们将来自 Web 应用的调用转换为特定于平台的 API。
Apache Cordova 项目维护着一组提供对各种原生设备功能(如相机、联系人或文件系统访问)访问的核心插件。但任何人都可以编写 Cordova 插件来执行原生代码可以执行的任何操作,并且许多第三方插件可用。您可以在Cordova 网站上搜索插件或直接在npm上搜索。
但是请注意,尽管核心插件通常维护良好并且与 Cordova 的其余部分保持最新,但第三方插件的质量可能有点冒险。您还必须确保您要使用的插件与Meteor 包含的 Cordova 平台版本兼容。
安装插件
插件由名称标识,该名称通常与其 npm 包名称相同。当前约定是插件名称以cordova-plugin-
开头,但并非所有第三方插件都遵守此约定。
您可以将 Cordova 插件直接添加到您的项目中,也可以作为 Meteor 包的依赖项添加。
如果要直接将插件添加到项目中,可以使用与 Meteor 包相同的meteor add
命令,但需要添加cordova:
前缀。
meteor add cordova:[email protected]
与 Meteor 包相比,您必须指定插件的确切版本。这可能有点麻烦,因为您首先需要查找插件的最新(兼容)版本是什么,然后才能添加它。
Meteor 包可以使用Cordova.depends()
语法注册对 Cordova 插件的依赖关系。例如,依赖于 Cordova 相机插件的 Meteor 包会将其package.js
添加如下内容
Cordova.depends({
'cordova-plugin-camera': '1.2.0'
});
这意味着将 Meteor 包添加到您的项目中也会安装指定的 Cordova 插件。
注意:如果多个 Meteor 包添加了同一个 Cordova 插件但版本不同,则无法明确确定最终安装哪个版本。但是,直接添加到项目的插件将始终覆盖作为包依赖项添加的相同插件的版本。
由于将插件安装到已经包含插件的 Cordova 项目中可能导致不确定的结果,因此每当对项目中的任何插件进行更改时,Meteor 都会删除并重新添加所有插件。
Cordova 从 npm 下载插件,并将其缓存(在~/.cordova/lib/npm_cache
中),因此如果重新构建或在另一个项目中再次使用它们,则不必重复下载。
确保插件与捆绑的 Cordova 平台版本兼容
由于插件版本和 Cordova 平台版本之间存在紧密耦合,因此您可能会遇到由于不兼容的插件导致的构建时或运行时错误。如果发生这种情况,您将必须安装不同的插件版本,或者事实证明某个插件(尚未)与我们捆绑的 Cordova 平台版本兼容。
为了帮助解决此问题,我们将核心插件固定到已知可与我们捆绑的 Cordova 版本一起使用的最低版本。但是,此机制不适用于第三方插件,因此您必须自行评估兼容性。
Cordova 项目正在进行的工作将改善这种情况,并使插件更容易指定其平台依赖项,以便 Cordova 可以确定兼容版本。
设置插件参数
某些 Cordova 插件需要在构建过程中设置某些参数。例如,com-phonegap-plugins-facebookconnect
要求您指定APP_ID
和APP_NAME
。您可以使用App.configurePlugin
在您的mobile-config.js中设置这些参数。
从 Git 安装插件
或者,如果对您想要使用的插件进行了未发布的更改,您也可以让 Cordova 从 Git 存储库下载插件代码。但是请注意,这将在每次重新构建时克隆插件存储库,因此这可能相当缓慢,应尽可能避免。与默认 Cordova 相比,Meteor 要求您指定提交的确切 SHA 哈希,而不是允许您引用分支或标签。这样做是为了保证构建的可重复性,并避免不必要的插件重新安装,因为只要 SHA 相同,我们就知道没有任何更改。
从 Git 添加插件的语法有点笨拙。名称(@
之前的部分)是插件 ID,必须与插件的plugin.xml
中指定的内容匹配。而不是版本,您指定一个指向 Git 存储库的 URL,并使用 SHA 哈希作为锚点(#
之后的部分)
meteor add cordova:com.phonegap.plugins.facebookconnect@https://github.com/Wizcorp/phonegap-facebook-plugin.git#5dbb1583168558b4447a13235283803151cb04ec
Meteor 包也可以依赖从 Git 下载的插件。
Cordova.depends({
'com.phonegap.plugins.facebookconnect': 'https://github.com/Wizcorp/phonegap-facebook-plugin.git#5dbb1583168558b4447a13235283803151cb04ec'
});
从本地文件系统安装插件
最后,特别是如果您正在开发自己的插件,从本地文件系统安装它可能是跟踪对插件代码所做更改的便捷方法。但是,这样做的缺点是 Meteor 将在每次构建时重新安装所有插件,因此这可能会大大降低速度。但是,我们确实使用--link
选项添加了本地插件,因此 Cordova 将尝试使用符号链接而不是复制它们来安装插件的文件,这意味着对文件的更改将反映在生成的原生项目(例如 Xcode 项目)中,并且可能不需要重新构建。
您可以通过指定file://
URL 来安装来自本地文件系统的插件,该 URL 相对于项目目录进行解释。
meteor add cordova:cordova-plugin-underdevelopment@file://../plugins/cordova-plugin-underdevelopment
Meteor 包也可以依赖从本地文件系统安装的插件,尽管这可能仅对本地包有意义。
Cordova.depends({
'cordova-plugin-underdevelopment': 'file://../plugins/cordova-plugin-underdevelopment'
});
删除直接安装的插件
您可以使用meteor remove
删除之前添加的插件。
meteor remove cordova:cordova-plugin-camera
meteor remove cordova:com.phonegap.plugins.facebookconnect
meteor remove cordova:cordova-plugin-underdevelopment
使用插件
您应该将任何依赖于 Cordova 插件的功能包装在Meteor.startup()
块中,以确保插件已完全初始化(通过侦听deviceready
事件)。例如,当使用 Cordova 地理位置插件时
// The plugin may not have been initialized here
navigator.geolocation.getCurrentPosition(success);
Meteor.startup(function() {
// Here we can be sure the plugin has been initialized
navigator.geolocation.getCurrentPosition(success);
});
在您的 JavaScript 代码中检测 Cordova
就像您可以使用Meteor.isServer
和Meteor.isClient
来分离您的客户端和服务器端代码一样,您可以使用Meteor.isCordova
来分离您的 Cordova 特定代码与代码的其余部分。
if (Meteor.isServer) {
console.log("Printed on the server");
}
if (Meteor.isClient) {
console.log("Printed in browsers and mobile apps");
}
if (Meteor.isCordova) {
console.log("Printed only in mobile Cordova apps");
}
此外,包可以使用addFiles
为 Cordova 构建和浏览器构建包含不同的文件集。
api.addFiles('foo.js', 'web.cordova')
:仅在 Cordova 构建中包含foo.js
。api.addFiles('bar.js', 'web.browser')
:仅在浏览器构建中包含bar.js
。api.addFiles('baz.js', 'web')
:在所有客户端构建中包含baz.js
。
相同的语法可用于api.use
、api.imply
和api.export
。
访问本地文件和远程资源
作为 Web 应用,Cordova 应用受各种旨在保护代码完整性和避免某些类型的攻击的安全机制的约束。使用的安全机制可能取决于应用运行的 Web 视图的类型和版本。此外,Cordova 本身,在某些情况下操作系统,会添加不同级别的访问控制,这也会影响可以加载和无法加载的内容。所有这些都可能使理解为什么某些内容无法正常工作变得相当混乱,甚至更难以理解各种配置这些机制的方式的安全含义。
本地文件
由于 Meteor 中的 Cordova 集成不会从file://
URL 提供您的应用,因此由于同源策略,也不允许通过file://
URL 访问本地文件。
但是,Meteor 中使用的文件服务机制允许通过以下形式的 URL 访问本地文件:https://127.0.0.1:<port>/local-filesystem/<path>
。您可以手动构建这些文件系统 URL,或使用WebAppLocalServer.localFileSystemUrl()
转换file://
URL。例如,您可以使用它来转换从cordova-plugin-file
和cordova-plugin-camera
等插件接收的 URL。
域白名单
Cordova 通过白名单机制控制对外部域的访问,该机制在我们在捆绑的 Cordova 版本中作为cordova-plugin-whitelist
实现。
在 Meteor 中,您使用App.accessRule
在mobile-config.js
中设置其他规则。(这些对应于生成的config.xml
中的<access>
、<allow-navigation>
和<allow-intent>
标签。)
在 iOS 上,这些设置还控制应用程序传输安全 (ATS),这是一种在 iOS 9 中新增的用于强制执行安全最佳实践的操作系统级机制。如果要连接到的服务器(尚未)满足这些要求,则可以使用其他选项为特定域覆盖它们。
App.accessRule('https://domain.com', { 'minimum-tls-version': 'TLSv1.0', 'requires-forward-secrecy': false, });
By default, Cordova apps in Meteor are only allowed access to `localhost` (the device itself, to serve the app from) and the server your app connects to for data loading and hot code push (either an automatically detected IP address an explicitly configured mobile server domain). These restrictions also apply to loading files in iframes and to opening files in other apps (including the mobile browser).
> Note that these restrictions mean you will have to explicitly allow loading `data:` URLs. For example, to allow loading `data:` URLs in iframes you would add:
> ```js
App.accessRule('data:*', { type: 'navigation' });
内容安全策略 (CSP)
除了 Cordova 实现的域白名单机制之外,Web 视图本身也可能通过内容安全策略 (CSP)强制执行访问规则。目前,Meteor 会向生成的索引页面添加一个宽松的<meta http-equiv="Content-Security-Policy" content="..."
标头。如果用户希望获得更细粒度的控制,Meteor 建议使用 Helmet。有关更多详细信息,请参阅指南
。
跨源资源共享 (CORS)
人们常常感到困惑的是,设置App.accessRule
不足以允许访问远程资源。虽然域白名单允许客户端控制可以连接到的域,但还会应用基于同源策略的其他限制。例如,默认情况下,Web 视图不允许从 JavaScript 发起的跨源 HTTP 请求,因此在使用XMLHttpRequest
时,您可能会遇到此问题。
要解决这些限制,您必须使用所谓的跨源资源共享 (CORS)。与在客户端配置的白名单机制相反,CORS 依赖于服务器设置的标头。换句话说,为了允许访问远程资源,您可能必须在服务器上进行配置更改,例如设置Access-Control-Allow-Origin
标头。
系统权限
自 iOS 8.0 和 Android 6.0(Android Marshmallow)发布以来,某些系统功能(例如相机、麦克风、位置、照片等)通常需要其他权限才能访问,并且对于 iOS 10+,您还必须提供自定义的隐私使用通知提示。Android 的这些值在应用的 `AndroidManifest.xml` 文件中指定,并且**也在运行时请求**。对于 iOS,它们在应用的 `Info.plist` 文件中指定。要在运行时请求它们,请考虑使用cordova.plugins.diagnostic
插件。
例如,这里我们为 WebRTC 会话准备了 Android 和 iOS 硬件权限。
meteor add cordova:[email protected]
if (Meteor.isCordova) {
cordova.plugins.diagnostic.isCameraAuthorized(
authorized => {
if (!authorized) {
cordova.plugins.diagnostic.requestCameraAuthorization(
granted => {
console.log( "Authorization request for camera use was " +
(granted ? "granted" : "denied"));
},
error => { console.error(error); }
);
}
},
error => { console.error(error); }
);
}
或者,对于 iOS,您可以在 mobile-config.js
中使用 App.appendToConfig
以及正确的 Cocoa Keys 来指定所需的隐私使用通知提示。
以下是如何访问 iOS 地理位置数据的示例
App.appendToConfig(`
<edit-config target="NSLocationWhenInUseUsageDescription" file="*-Info.plist" mode="merge">
<string>My app needs access to your location for navigation purposes</string>
</edit-config>
`);
配置您的应用
Meteor 在构建期间读取应用目录根目录下的 mobile-config.js
文件,并使用其中指定的设置生成 Cordova 的 config.xml
文件。
元数据
App.info({
id: 'com.meteor.examples.todos',
name: 'Todos',
version: "0.0.1"
});
首选项
App.setPreference('BackgroundColor', '0xff0000ff');
App.setPreference('Orientation', 'default');
App.setPreference('Orientation', 'all', 'ios');
请参阅 Meteor 的移动配置 文档和 Cordova 文档的首选项部分,以获取有关 Meteor 的 Cordova 配置 API 和支持选项的更多信息。
应用图标和启动画面
虽然 Meteor 包含一组标准的应用图标和启动画面,但您需要在 mobile-config.js
文件中配置自己的图像以匹配应用的品牌。
您可以使用 App.icons
和 App.launchScreens
中支持的特定设置来配置图标和启动画面图像大小。
此外,iOS 上的 Cordova 支持使用 启动故事板图像,这是 Apple 目前推荐的提供启动画面的方法。这样做的好处是您无需为每个可能的设备屏幕尺寸提供图像。从您的 mobile-config.js
中删除所有 iOS App.launchScreens
指令,并使用 App.appendToConfig
添加通用图像的路径。
App.appendToConfig(`
<splash src="../../../app/path/to/Default@2x~universal~anyany.png" />
<splash src="../../../app/path/to/Default@3x~universal~anyany.png" />
`);
有关更多信息,请参阅 iOS 人机界面指南中的图标和图像尺寸。
在 iPhone X 上,如果您希望启动图像覆盖整个屏幕,则可能需要使用启动故事板图像。还有一些其他需要解决的应用布局问题,例如“安全区域”和“圆角”,请参阅 Apple 的 iOS 应用更新以适配 iPhone X。
高级构建自定义
有一个名为 cordova-build-override/
的特殊顶级目录,它允许您以临时的方式覆盖 Meteor 为您在 .meteor/local/cordova-build
目录中生成的 Cordova 项目的部分内容。此目录的整个文件树将在构建和编译步骤之前被 cp -R
(复制并覆盖现有文件)到 Cordova 项目中。
此机制的问题在于它会覆盖完整的文件,因此它不是自定义 config.xml
的好方法。用您自己的文件替换生成的版本意味着您将丢失构建过程和已安装插件设置的所有配置信息,这可能会导致您的应用崩溃。
如果您需要自定义配置文件,一种解决方法是创建一个虚拟 Cordova 插件。在其 plugin.xml
中,您可以指定 config-file
元素 来选择性地更改配置文件的部分内容,包括 config.xml
。
我们建议仅在绝对必要且您的自定义无法通过标准配置选项处理时才使用这些方法。
部署到生产环境
构建生产版本
使用 meteor build <build-output-directory> --server=<host>:<port>
构建您的应用以用于生产环境。
<host>
和 <port>
应该是您希望应用连接到的服务器的地址。
这将在 <build-output-directory>
中生成一个目录,其中包括服务器捆绑包 tarball 以及每个目标移动平台的项目源代码(位于 /ios
和 /android
目录中)。
如果您传递 --debug
,则捆绑包将以 Cordova 的调试模式而不是发布模式进行编译。在 Android 上,这将生成一个 <build-output-directory>/android/debug.apk
文件,该文件无需签名即可安装。
您可以传递 --server-only
以仅构建服务器捆绑包。这允许您在不安装构建机器上的移动 SDK 的情况下构建您的应用。例如,如果您使用自动部署设置,这将非常有用。(如果您在构建之前删除了移动平台,则热代码推送将被禁用,因为服务器捆绑包中包含的 Cordova 资产将不会生成。)
iOS App Store
为了构建您的 iOS 应用,您需要 配置您的应用,至少需要版本号以及所需的应用图标和启动画面集。
运行 meteor build
后,您可以在 Xcode 中打开生成的 Xcode 项目。
cd <build-output-directory>/ios/project
open MyApp.xcodeproj
从这一点开始,构建应用存档并将其提交到 App Store 的过程与任何其他 iOS 应用相同。有关更多详细信息,请参阅 Apple 的文档。
Android Play Store
为了构建您的 Android 应用,您需要 配置您的应用,至少需要版本号以及所需的应用图标和启动画面集。
运行 meteor build
后,生成的 APK 将从 <build-output-directory>/android/project/build/outputs/apk/release
目录复制到 <build-output-directory>/android/release-unsigned.apk
。
如果您已安装 Crosswalk,则需要手动复制 APK 文件
cp ~/build-output-directory/android/project/build/outputs/apk/android-armv7-release-unsigned.apk ~/build-output-directory/android/release-unsigned.apk
在将 APK(s) 提交到 Play Store 之前,您需要对 APK 进行签名并运行 zipalign
来优化存档。
(有关应用签名过程的更多详细信息,请参阅 Android 开发人员文档。)
要对您的应用进行签名,您需要一个私钥。此密钥允许您发布和更新您的应用。如果您尚未为此应用创建密钥,请运行
keytool -genkey -alias your-app-name -keyalg RSA -keysize 2048 -validity 10000
或者,您可以指定 --keystore
来使用不同的密钥库。签名 APK 时不要忘记指定相同的密钥库。
注意:确保您拥有密钥库的安全的备份(
~/.keystore
是默认值)。如果您将应用发布到 Play Store,然后丢失了用于签名应用的密钥,则您将无法发布任何应用更新,因为您必须始终使用相同的密钥对所有版本的应用进行签名。
现在,您可以对 APK 进行签名
cd ~/build-output-directory/android/
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 release-unsigned.apk your-app-name
接下来,您可以运行 zipalign 对其进行优化
$ANDROID_HOME/build-tools/<build-tools-version>/zipalign 4 release-unsigned.apk <your-app-name>.apk
从这一点开始,将应用提交到 Play Store 的过程与任何其他 Android 应用相同。<your-app-name>.apk
是要上传到商店的 APK。访问 https://play.google.com/apps/publish 了解更多信息。
使用 Crosswalk 将应用提交到 Play Store
由于 Crosswalk 捆绑了 Chromium 的原生代码,因此您最终将获得 ARM 和 x86 的 APK。您可以在 <build-output-directory>/android/project/build/outputs/apk
目录中找到生成的 APK。
您需要对这两个 APK 进行签名和 zipalign
。您还需要将两者都提交到 Play Store,请参阅 提交多个 APK 以获取更多信息。