跳到主要内容
版本:v4

将应用中的 Capacitor 升级至 3.0

Capacitor 3 为生态系统带来了重要更新和令人兴奋的新功能。

阅读 Capacitor 3.0 公告 ›

在将应用升级至 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 和核心库

npm install @capacitor/cli@latest-3 @capacitor/core@latest-3

ES2017+

Capacitor 3 现在构建目标是 ES2017 环境,而非 ES5。插件模板也已更新为 ES2017 目标,鼓励第三方插件也更新其目标。

除非您的应用需要支持 IE11(Capacitor 官方不支持),否则这一变更不会影响您的应用。

TypeScript 3.8+

Capacitor 3 使用了需要 TypeScript 3.8 或更高版本的新语法。

Capacitor 配置变更

如果已安装 TypeScript 3.8+,您可以将 capacitor.config.json 迁移为一个类型化的 TypeScript 配置文件 capacitor.config.ts。您仍可使用 .json 文件,但 TypeScript 配置文件能为团队提供更好的开发体验。以下是 Capacitor 测试应用中使用的 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 核心库中移除,并分别发布为独立的 npm 包。这样做有多方面原因(参见 #3227),核心团队确信这是正确的方向。您可以这样导入核心插件:

import { Camera } from '@capacitor/camera';

移除了后台任务、权限和照片插件

  • Background Task:该插件使用率低且功能不符合大多数开发者预期。核心团队将在未来重新设计后台功能。关注 #3032 获取更新。
  • Permissions:核心团队已实现了一种替代方案(参见新版权限 API),社区插件也可采用。
  • Photos:这个未文档化的 iOS 专属插件已被移除。请使用 @capacitor-community/media

拆分辅助功能、应用和模态框插件

  • Accessibility
  • App
    • 应用相关信息和功能保留在 App
    • 应用 URL 处理(openUrl()canOpenUrl())移至 App Launcher
  • Modals
    • 操作表功能(showActions())移至 Action Sheet
    • 对话框功能(alert()prompt()confirm())移至 Dialog

迁移应用到新版官方插件包

这一变更要求您单独安装每个正在使用的插件。

  1. 在项目中搜索从 @capacitor/corePlugins 对象提取的核心插件
  2. 查找对应的插件文档,注意部分插件已被拆分
  3. 按照文档中的安装说明操作
  4. 将插件导入改为从插件包导入(参见插件导入
  5. 遵循向后不兼容的插件变更中的说明

使用 Ionic Framework?

Ionic Framework 使用了以下插件中的 API:

为了获得最佳用户体验,即使应用中未直接导入这些插件,也应确保它们已安装:

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 保持不变以简化迁移过程,但某些变更需要代码更新和手动迁移。

  • Accessibility / Screen Reader
    • isScreenReaderEnabled() 方法已重命名为 isEnabled()
    • 'accessibilityScreenReaderStateChange' 事件已重命名为 'stateChange'
    • 在 Android 和 iOS 上,speak() 仅当屏幕阅读器激活时有效。如需无论屏幕阅读器状态都支持文本转语音,请使用 @capacitor-community/text-to-speech
  • Browser
    • 移除了 prefetch()
  • Device
    • getInfo() 中移除了应用信息(appVersionappBuildappIdappName)。使用 App 插件的 getInfo() 获取这些信息。
    • getInfo() 中移除了 uuid。使用新的 getId() 函数。
  • Haptics
    • HapticsNotificationType 枚举键已从大写改为驼峰式以匹配其他枚举。
  • Local Notifications
    • 该插件现在使用新版权限 API。移除了 requestPermission(),请使用 requestPermissions()
  • Push Notifications
    • 该插件现在使用新版权限 API。移除了 requestPermission(),请使用 requestPermissions()
  • Share
    • share() 方法现在返回 ShareResult 而非 any
    • share() 的返回值不再包含 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 文件夹

  1. 展开 App 项目下的文件树,然后选择 App 组中的 public 文件夹
  2. 右键点击 Delete。当提示删除文件夹或仅移除引用时,选择 Move to Trash

删除 public 文件夹

在新位置重建 public

  1. 右键点击 App 项目中的 App 组,点击 Add Files to "App"...
  2. 保留默认选项(确保创建文件夹引用而非组,并添加到 App 目标)
  3. 点击 New Folder,命名为 "public"
  4. 点击 Create,然后 Add

重建 public 文件夹

在 Xcode 中看起来可能相同,但新的 public 文件夹现在应相对于 App 组而非项目根目录。

在 gitignore 中添加新的 public 文件夹

ios/.gitignore 中,将忽略路径从 App/public 改为 App/App/public。此文件夹包含您的网页资产副本,不应提交。

 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

ios/.gitignore 文件中添加 DerivedData。这是 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。在