在您的应用中将 Capacitor 更新到 3.0
Capacitor 3 为生态系统带来了关键更新和令人兴奋的新功能。
将您的应用升级到 Capacitor 3 后,您能否在此讨论中分享您的反馈?我们很乐意听取您的意见!💖
如果您是插件作者,希望将插件升级到更新的 Capacitor 版本,请参阅Capacitor 插件升级指南。
NodeJS 12+
Node 8 已达到生命周期结束。Node 10 将于 2021 年 4 月 30 日达到生命周期结束。Capacitor 3 需要 NodeJS 12 或更高版本。(建议使用最新的 LTS 版本。)
Ionic CLI
如果您使用 Ionic CLI,官方 Capacitor 3 支持从版本 6.16.0 开始。我们建议此时通过 npm install -g @ionic/cli 升级到最新版本。
更新 Capacitor CLI 和 Core
npm install @capacitor/cli@latest-3 @capacitor/core@latest-3
ES2017+
Capacitor 3 现在为 ES2017 环境构建,而不是 ES5。插件模板也已更新以针对 ES2017,鼓励第三方插件更新其目标。
此更改不应影响您的应用,除非您支持 IE11,Capacitor 不正式支持 IE11。
TypeScript 3.8+
Capacitor 3 使用只能在 TS 3.8 或更高版本中使用的更新的 TypeScript 语法。
Capacitor 配置更改
如果您安装了 TypeScript 3.8+,您可以将 capacitor.config.json 迁移为名为 capacitor.config.ts 的类型化 TypeScript 配置文件。您可以继续使用 .json 文件,但 typescript 配置文件可能会为您的团队提供更好的开发人员体验。下面是 Capacitor Test App 中使用的示例 capacitor.config.ts 文件。
/// <reference types="@capacitor/local-notifications" />
/// <reference types="@capacitor/push-notifications" />
/// <reference types="@capacitor/splash-screen" />
import { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.capacitorjs.app.testapp',
appName: 'capacitor-testapp',
webDir: 'build',
plugins: {
SplashScreen: {
launchAutoHide: false,
},
LocalNotifications: {
smallIcon: 'ic_stat_icon_config_sample',
iconColor: '#CE0B7C',
},
PushNotifications: {
presentationOptions: ['alert', 'sound'],
},
},
};
export default config;
官方插件
所有插件已从 Capacitor core 中删除并放入自己的 npm 包中。这有几个原因(参见 #3227),核心团队确信这是正确的方法。您可以像这样导入核心插件。
import { Camera } from '@capacitor/camera';
删除了 Background Task、Permissions 和 Photos 插件
- Background Task:此插件似乎很少使用,并且不能像大多数开发人员期望的那样工作。核心团队将在未来重新解决后台功能。订阅 #3032 以获取更新。
- Permissions:核心团队已经实现了这种集中化方法的替代方案,社区插件也可以采用(参见新权限 API)。
- Photos:这个未记录的仅 iOS 的插件已被删除。请使用
@capacitor-community/media。
拆分的 Accessibility、App 和 Modals 插件
- Accessibility
- VoiceOver 和 TalkBack 功能移至 Screen Reader
- App
- 应用相关信息和功能保留在 App 中
- 应用 URL 处理(
openUrl()和canOpenUrl())移至 App Launcher
- Modals
- Action Sheet 功能(
showActions())移至 Action Sheet - 对话窗口功能(
alert()、prompt()和confirm())移至 Dialog
- Action Sheet 功能(
迁移您的应用以使用新的官方插件包
此更改将要求您单独安装您使用的每个插件。
- 在项目中搜索从
@capacitor/core的Plugins对象中提取的核心插件 - 找到相应的插件文档,请记住某些插件已被拆分
- 按照文档中每个插件的安装说明进行操作
- 更改插件导入以从插件的包导入(参见插件导入)
- 按照向后不兼容的插件更改中的说明进行操作
使用 Ionic Framework?
Ionic Framework 使用以下插件中的 API:
为了获得与 Ionic Framework 的最佳用户体验,您应该确保安装这些插件,即使您不在应用中导入它们:
npm install @capacitor/app @capacitor/haptics @capacitor/keyboard @capacitor/status-bar
插件导入
Plugins 对象已弃用,但将继续在 Capacitor 3 中工作。Capacitor 插件应该更新以使用新的插件注册 API(参见插件升级指南),这将允许它们直接从插件的包导入。
今后,不应使用来自 @capacitor/core 的 Plugins 对象。
// 旧
import { Plugins } from '@capacitor/core';
const { AnyPlugin } = Plugins;
最好直接从插件的包导入插件,但插件必须更新以与 Capacitor 3 一起工作,这才能实现。
// 新
import { AnyPlugin } from 'any-plugin';
向后不兼容的插件更改
虽然许多插件 API 保持不变以简化到 Capacitor 3 的迁移过程,但有些插件需要代码更新和手动迁移。
- Accessibility / Screen Reader
isScreenReaderEnabled()方法已重命名为isEnabled()'accessibilityScreenReaderStateChange'事件已重命名为'stateChange'- 在 Android 和 iOS 上,
speak()仅在屏幕阅读器当前处于活动状态时才工作。对于在屏幕阅读器处于活动状态或未处于活动状态时的文本转语音功能,请使用@capacitor-community/text-to-speech。
- Browser
prefetch()已删除。
- Device
- 应用信息已从
getInfo()中删除(appVersion、appBuild、appId和appName)。请使用 App 插件的getInfo()获取此信息。 uuid已从getInfo()中删除。请使用新的getId()函数。
- 应用信息已从
- Haptics
HapticsNotificationType枚举键已从大写更改为驼峰命名,以匹配其他枚举。
- Local Notifications
- 此插件现在使用新的权限 API。
requestPermission()已删除,请使用requestPermissions()。
- 此插件现在使用新的权限 API。
- Push Notifications
- 此插件现在使用新的权限 API。
requestPermission()已删除,请使用requestPermissions()。
- 此插件现在使用新的权限 API。
- Share
share()方法现在返回ShareResult而不是anyshare()的返回值将不再包含completed。如果未完成,它将拒绝。
- Storage
- 需要数据迁移! 内部存储机制已更改,需要数据迁移。已添加一个便利方法:
migrate()。要在不影响最终用户的情况下更新您的应用,请在任何其他方法之前调用migrate()。
- 需要数据迁移! 内部存储机制已更改,需要数据迁移。已添加一个便利方法:
- Filesystem
stat()方法现在在所有平台上以毫秒为单位返回 ctime 和 mtime 时间戳。以前,iOS 以秒为单位返回时间戳。
日志记录更改
在 Capacitor 3 中,hideLogs 配置选项已被弃用。它已被新的 loggingBehavior 配置选项取代。详细信息可以在配置文档中找到
iOS
Capacitor 3 支持 iOS 12+。需要 Xcode 12+。建议使用 CocoaPods 1.8+。
更新 CocoaPods
建议升级到最新稳定版本的 CocoaPods。CocoaPods 1.8 切换到使用 CDN,这意味着不再需要定期运行 pod repo update。
使用 pod --version 检查您的 CocoaPods 版本,并访问 cocoapods.org 获取安装说明。
将 iOS 部署目标设置为 12.0
为您的 Xcode 项目和应用目标执行以下操作:打开 Build Settings 选项卡。在 Deployment 部分下,将 iOS Deployment Target 更改为 iOS 12.0。
然后,打开 ios/App/Podfile 并将 iOS 版本更新到 12.0:
-platform :ios, '11.0'
+platform :ios, '12.0'
use_frameworks!
将 Swift 版本设置为 5
如果您的应用尚未使用 Swift 5,请在 Xcode 目标中打开 Build Settings 选项卡,然后在 Swift Compiler - Language 部分下将 Swift Language Version 更改为 Swift 5。
将 public 移动到 iOS 目标目录
在 Capacitor 3 中,建议将 ios/App/public 目录移动到 ios/App/App/public。这可以在 Xcode 中实现:
删除现有的 public 文件夹
- 展开
App项目下的文件树,然后展开App组,并选择public文件夹。 - 右键单击 Delete。当提示删除文件夹还是仅删除引用时,选择 Move to Trash。

在新位置重新创建 public
- 右键单击
App项目中的App组,然后单击 Add Files to "App"... - 保留默认选项(确保创建文件夹引用,而不是组,并添加到
App目标)。 - 单击 New Folder,将其命名为 "public"。
- 单击 Create,然后单击 Add。

它在 Xcode 中可能看起来相同,但新的 public 文件夹现在应该相对于 App 组,而不是项目根目录。
gitignore 新的 public 文件夹
在 ios/.gitignore 中,将忽略路径从 App/public 更改为 App/App/public。此文件夹包含 Web 资产的副本,不应提交。
App/build
App/Pods
-App/public
+App/App/public
App/Podfile.lock
xcuserdata
更新 Capacitor iOS 平台
npm install @capacitor/ios@latest-3
npx cap sync ios
在应用事件中从 CAPBridge 切换到 ApplicationDelegateProxy
在 ios/App/App/AppDelegate.swift 中,更新以下内容:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
// Called when the app was launched with a url. Feel free to add additional processing here,
// but if you want the App API to support tracking app url opens, make sure to keep this call
- return CAPBridge.handleOpenUrl(url, options)
+ return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
// Called when the app was launched with an activity, including Universal Links.
// Feel free to add additional processing here, but if you want the App API to support
// tracking app url opens, make sure to keep this call
- return CAPBridge.handleContinueActivity(userActivity, restorationHandler)
+ return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
}
删除 USE_PUSH 编译条件
如果使用推送通知功能,在 ios/App/App/AppDelegate.swift 中,更新以下内容:
- #if USE_PUSH
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
NotificationCenter.default.post(name: Notification.Name(CAPNotifications.DidRegisterForRemoteNotificationsWithDeviceToken.name()), object: deviceToken)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
NotificationCenter.default.post(name: Notification.Name(CAPNotifications.DidFailToRegisterForRemoteNotificationsWithError.name()), object: error)
}
-#endif
如果不使用推送通知,您可以删除整个块
- #if USE_PUSH
-
- func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
- NotificationCenter.default.post(name: Notification.Name(CAPNotifications.DidRegisterForRemoteNotificationsWithDeviceToken.name()), object: deviceToken)
- }
-
- func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
- NotificationCenter.default.post(name: Notification.Name(CAPNotifications.DidFailToRegisterForRemoteNotificationsWithError.name()), object: error)
- }
-
-#endif
从硬编码的 CAPNotifications 切换到 NSNotification 扩展
在 ios/App/App/AppDelegate.swift 中,更新以下内容:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
let statusBarRect = UIApplication.shared.statusBarFrame
guard let touchPoint = event?.allTouches?.first?.location(in: self.window) else { return }
if statusBarRect.contains(touchPoint) {
- NotificationCenter.default.post(CAPBridge.statusBarTappedNotification)
+ NotificationCenter.default.post(name: .capacitorStatusBarTapped, object: nil)
}
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
- NotificationCenter.default.post(name: Notification.Name(CAPNotifications.DidRegisterForRemoteNotificationsWithDeviceToken.name()), object: deviceToken)
+ NotificationCenter.default.post(name: .capacitorDidRegisterForRemoteNotifications, object: deviceToken)
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
- NotificationCenter.default.post(name: Notification.Name(CAPNotifications.DidFailToRegisterForRemoteNotificationsWithError.name()), object: error)
+ NotificationCenter.default.post(name: .capacitorDidFailToRegisterForRemoteNotifications, object: error)
}
忽略 DerivedData
将 DerivedData 添加到 ios/.gitignore 文件。这是 Capacitor CLI 放置原生 iOS 构建的位置。
App/Pods
App/App/public
App/Podfile.lock
+DerivedData
xcuserdata
# Cordova plugins for Capacitor
Android
Capacitor 3 支持 Android 5+(现在支持 Android 11)。需要 Android Studio 4+。
更新 Capacitor Android 平台
npm install @capacitor/android@latest-3
npx cap sync android
切换到自动 Android 插件加载
在 Capacitor 3 中,最好自动加载 Android 插件。在 MainActivity.java 中,可以删除 onCreate 方法。在添加或删除通过 npm 安装的插件时 ,您不再需要编辑此文件。
public class MainActivity extends BridgeActivity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Initializes the Bridge
- this.init(savedInstanceState, new ArrayList<Class<? extends Plugin>>() {{
- // Additional plugins you've installed go here
- add(Plugin1.class);
- add(Plugin2.class);
- }});
- }
}
如果您的应用包含专门为您的应用构建的自定义插件,您仍然必须在 onCreate 中注册插件:
public class MainActivity extends BridgeActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ registerPlugin(PluginInMyApp.class);
}
}
更新 Gradle 到 7.0
我们现在建议在 Capacitor 项目中使用 Gradle 7.0。在 Android Studio 中,打开 File 菜单,然后单击 Project Structure。在 Project 部分中,将 Gradle Version 更改为 7.0,将 Android Gradle Plugin Version 更改为 4.2.0。然后,单击 OK。
您可能希望在 Project Structure 对话框的 Suggestions 部分中评估对 Android 包的建议更新。
更新 Android 变量
在 android/variables.gradle 中,您可以更新以下变量:
ext {
minSdkVersion = 21
- compileSdkVersion = 29
- targetSdkVersion = 29
+ compileSdkVersion = 30
+ targetSdkVersion = 30
+ androidxActivityVersion = '1.2.0'
- androidxAppCompatVersion = '1.1.0'
+ androidxAppCompatVersion = '1.2.0'
+ androidxCoordinatorLayoutVersion = '1.1.0'
- androidxCoreVersion = '1.2.0'
- androidxMaterialVersion = '1.1.0-rc02'
- androidxBrowserVersion = '1.2.0'
- androidxLocalbroadcastmanagerVersion = '1.0.0'
- androidxExifInterfaceVersion = '1.2.0'
- firebaseMessagingVersion = '20.1.2'
- playServicesLocationVersion = '17.0.0'
+ androidxCoreVersion = '1.3.2'
+ androidxFragmentVersion = '1.3.0'
- junitVersion = '4.12'
- androidxJunitVersion = '1.1.1'
- androidxEspressoCoreVersion = '3.2.0'
+ junitVersion = '4.13.1'
+ androidxJunitVersion = '1.1.2'
+ androidxEspressoCoreVersion = '3.3.0'
cordovaAndroidVersion = '7.0.0'
}
Capacitor 3 支持 Android 11 (API 30),因此您可以将 SDK 目标更新到 30。将 compileSdkVersion 和 targetSdkVersion 更改为 30。
有一个新的 androidxActivityVersion 变量可用,添加值为 1.2.0。
androidxAppCompatVersion 可以更新到 1.2.0。
有一个新的 androidxCoordinatorLayoutVersion 变量可用,添加值为 1.1.0。
androidxCoreVersion 可以更新到 1.3.2。
androidxMaterialVersion 变量被 Action Sheet 和 Camera 插件使用,如果不使用它们,可以删除。如果使用它们,请检查 Camera 文档 和 Action Sheet 文档。
androidxBrowserVersion 变量被 Browser 插件使用,如果不使用该插件,可以删除。如果使用该插件,请检查文档。
androidxLocalbroadcastmanagerVersion 变量可以删除。
androidxExifInterfaceVersion 变量被 Camera 插件使用,如果不使用该插件,可以删除。如果使用该插件,请检查文档。
firebaseMessagingVersion 变量被 Push Notifications 插件使用,如果不使用该插件,可以删除。如果使用该插件,请检查文档。
playServicesLocationVersion 变量被 Geolocation 插件使用,如果不使用该插件,可以删除。如果使用该插件,请检查文档。
有一个新的 androidxFragmentVersion 变量可用,添加值为 1.3.0。
junitVersion 可以更新到 4.13.1。
androidxJunitVersion 可以更新到 1.1.2。
androidxEspressoCoreVersion 可以更新到 3.3.0。
删除未使用的和冗余的权限
根据您使用的插件,您可以选择从应用的 AndroidManifest.xml 文件中删除未使用的权限。新 Capacitor 应用中的清单仅包含 INTERNET,因为权限现在应该在安装插件时添加。按照以下步骤删除未使用的权限:
- 确定您的应用使用的插件
- 阅读每个插件的安装说明在这些文档中,查找每个插件所需的权限
- 在应用的
AndroidManifest.xml文件中,保留您的插件所需的权限,删除未使用的权限
Haptics 和 Network 插件是现在在其自己的 AndroidManifest.xml 文件中包含其安装时权限的插件示例,这些文件最终会与您的应用合并。可以安全地从应用的 AndroidManifest.xml 文件中删除它们的权限:
<!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" />
- <!-- Network API -->
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <!-- Vibration API -->
- <uses-permission android:name="android.permission.VIBRATE" />
</manifest>