原生代码调用 #
一、原生代码调用概述 #
1.1 调用方式 #
| 方式 | 说明 |
|---|---|
| 插件方式 | 创建独立插件,推荐 |
| 内联方式 | 直接在原生项目中编写代码 |
| 第三方库 | 使用Cordova插件 |
1.2 适用场景 #
- 需要访问特定平台API
- 集成原生SDK
- 性能敏感操作
- 平台特定功能
二、iOS原生代码 #
2.1 创建Swift插件文件 #
swift
// ios/App/App/Plugins/MyNativePlugin.swift
import Foundation
import Capacitor
import UIKit
@objc(MyNativePlugin)
public class MyNativePlugin: CAPPlugin {
@objc func getDeviceInfo(_ call: CAPPluginCall) {
let device = UIDevice.current
let result: [String: Any] = [
"name": device.name,
"model": device.model,
"systemName": device.systemName,
"systemVersion": device.systemVersion,
"identifier": device.identifierForVendor?.uuidString ?? ""
]
call.resolve(result)
}
@objc func openSettings(_ call: CAPPluginCall) {
DispatchQueue.main.async {
if let url = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(url)
call.resolve()
} else {
call.reject("Cannot open settings")
}
}
}
@objc func vibrate(_ call: CAPPluginCall) {
let style = call.getString("style") ?? "medium"
DispatchQueue.main.async {
let generator = UIImpactFeedbackGenerator(
style: style == "heavy" ? .heavy :
style == "light" ? .light : .medium
)
generator.prepare()
generator.impactOccurred()
call.resolve()
}
}
}
2.2 创建Objective-C桥接 #
objectivec
// ios/App/App/Plugins/MyNativePlugin.m
#import <Capacitor/Capacitor.h>
CAP_PLUGIN(MyNativePlugin, "MyNativePlugin",
CAP_PLUGIN_METHOD(getDeviceInfo, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(openSettings, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(vibrate, CAPPluginReturnPromise);
)
2.3 注册插件 #
swift
// ios/App/App/AppDelegate.swift
import UIKit
import Capacitor
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
return true
}
override func application(_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
}
}
2.4 JavaScript调用 #
typescript
// src/plugins/my-native-plugin.ts
import { registerPlugin } from '@capacitor/core';
interface MyNativePlugin {
getDeviceInfo(): Promise<{
name: string;
model: string;
systemName: string;
systemVersion: string;
identifier: string;
}>;
openSettings(): Promise<void>;
vibrate(options: { style?: 'light' | 'medium' | 'heavy' }): Promise<void>;
}
const MyNativePlugin = registerPlugin<MyNativePlugin>('MyNativePlugin');
export { MyNativePlugin };
typescript
// 使用
import { MyNativePlugin } from './plugins/my-native-plugin';
async function getDeviceInfo() {
const info = await MyNativePlugin.getDeviceInfo();
console.log('Device:', info);
}
async function openSettings() {
await MyNativePlugin.openSettings();
}
async function vibrate() {
await MyNativePlugin.vibrate({ style: 'medium' });
}
三、Android原生代码 #
3.1 创建Java插件 #
java
// android/app/src/main/java/com/company/app/plugins/MyNativePlugin.java
package com.company.app.plugins;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings;
import com.getcapacitor.JSObject;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;
import com.getcapacitor.annotation.CapacitorPlugin;
@CapacitorPlugin(name = "MyNativePlugin")
public class MyNativePlugin extends Plugin {
@PluginMethod
public void getDeviceInfo(PluginCall call) {
JSObject result = new JSObject();
result.put("manufacturer", Build.MANUFACTURER);
result.put("model", Build.MODEL);
result.put("brand", Build.BRAND);
result.put("device", Build.DEVICE);
result.put("sdkVersion", Build.VERSION.SDK_INT);
result.put("releaseVersion", Build.VERSION.RELEASE);
call.resolve(result);
}
@PluginMethod
public void openSettings(PluginCall call) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getContext().getPackageName(), null);
intent.setData(uri);
try {
getActivity().startActivity(intent);
call.resolve();
} catch (Exception e) {
call.reject("Cannot open settings: " + e.getMessage());
}
}
@PluginMethod
public void vibrate(PluginCall call) {
String style = call.getString("style", "medium");
int duration;
switch (style) {
case "light":
duration = 10;
break;
case "heavy":
duration = 100;
break;
default:
duration = 50;
}
Vibrator vibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
if (vibrator != null && vibrator.hasVibrator()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vibrator.vibrate(VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE));
} else {
vibrator.vibrate(duration);
}
}
call.resolve();
}
}
3.2 注册插件 #
java
// android/app/src/main/java/com/company/app/MainActivity.java
package com.company.app;
import android.os.Bundle;
import com.company.app.plugins.MyNativePlugin;
import com.getcapacitor.BridgeActivity;
public class MainActivity extends BridgeActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
// 注册插件
registerPlugin(MyNativePlugin.class);
super.onCreate(savedInstanceState);
}
}
3.3 Kotlin实现 #
kotlin
// android/app/src/main/java/com/company/app/plugins/MyNativePlugin.kt
package com.company.app.plugins
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.VibrationEffect
import android.os.Vibrator
import android.provider.Settings
import com.getcapacitor.JSObject
import com.getcapacitor.Plugin
import com.getcapacitor.PluginCall
import com.getcapacitor.PluginMethod
import com.getcapacitor.annotation.CapacitorPlugin
@CapacitorPlugin(name = "MyNativePlugin")
class MyNativePlugin : Plugin() {
@PluginMethod
fun getDeviceInfo(call: PluginCall) {
val result = JSObject().apply {
put("manufacturer", Build.MANUFACTURER)
put("model", Build.MODEL)
put("brand", Build.BRAND)
put("device", Build.DEVICE)
put("sdkVersion", Build.VERSION.SDK_INT)
put("releaseVersion", Build.VERSION.RELEASE)
}
call.resolve(result)
}
@PluginMethod
fun openSettings(call: PluginCall) {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.fromParts("package", context.packageName, null)
}
try {
activity.startActivity(intent)
call.resolve()
} catch (e: Exception) {
call.reject("Cannot open settings: ${e.message}")
}
}
@PluginMethod
fun vibrate(call: PluginCall) {
val style = call.getString("style", "medium")
val duration = when (style) {
"light" -> 10L
"heavy" -> 100L
else -> 50L
}
val vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
if (vibrator.hasVibrator()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vibrator.vibrate(
VibrationEffect.createOneShot(
duration,
VibrationEffect.DEFAULT_AMPLITUDE
)
)
} else {
vibrator.vibrate(duration)
}
}
call.resolve()
}
}
四、传递复杂数据 #
4.1 传递对象 #
typescript
// JavaScript
await MyNativePlugin.processData({
user: {
id: 1,
name: 'John',
preferences: {
theme: 'dark',
language: 'en'
}
},
items: [1, 2, 3, 4, 5]
});
swift
// iOS
@objc func processData(_ call: CAPPluginCall) {
guard let user = call.getObject("user"),
let items = call.getArray("items") as? [Int] else {
call.reject("Invalid data")
return
}
let userId = user["id"] as? Int
let userName = user["name"] as? String
let preferences = user["preferences"] as? [String: Any]
// 处理数据...
call.resolve([
"success": true,
"processedItems": items.count
])
}
java
// Android
@PluginMethod
public void processData(PluginCall call) {
JSObject user = call.getObject("user");
JSArray items = call.getArray("items");
if (user == null || items == null) {
call.reject("Invalid data");
return;
}
int userId = user.getInteger("id");
String userName = user.getString("name");
JSObject preferences = user.getJSObject("preferences");
// 处理数据...
JSObject result = new JSObject();
result.put("success", true);
result.put("processedItems", items.length());
call.resolve(result);
}
4.2 返回复杂数据 #
swift
// iOS
@objc func getComplexData(_ call: CAPPluginCall) {
let result: [String: Any] = [
"status": "success",
"data": [
"users": [
["id": 1, "name": "John"],
["id": 2, "name": "Jane"]
],
"meta": [
"total": 2,
"page": 1
]
]
]
call.resolve(result)
}
java
// Android
@PluginMethod
public void getComplexData(PluginCall call) {
JSObject result = new JSObject();
result.put("status", "success");
JSArray users = new JSArray();
users.put(new JSObject().put("id", 1).put("name", "John"));
users.put(new JSObject().put("id", 2).put("name", "Jane"));
JSObject meta = new JSObject();
meta.put("total", 2);
meta.put("page", 1);
JSObject data = new JSObject();
data.put("users", users);
data.put("meta", meta);
result.put("data", data);
call.resolve(result);
}
五、事件通知 #
5.1 原生向JS发送事件 #
swift
// iOS
@objc func startListening(_ call: CAPPluginCall) {
// 开始监听某些事件
// 发送事件到JS
notifyListeners("onDataReceived", data: [
"message": "Data received from native",
"timestamp": Date().timeIntervalSince1970
])
call.resolve()
}
java
// Android
@PluginMethod
public void startListening(PluginCall call) {
// 开始监听某些事件
// 发送事件到JS
JSObject data = new JSObject();
data.put("message", "Data received from native");
data.put("timestamp", System.currentTimeMillis());
notifyListeners("onDataReceived", data);
call.resolve();
}
5.2 JavaScript监听事件 #
typescript
import { MyNativePlugin } from './plugins/my-native-plugin';
// 添加监听器
await MyNativePlugin.addListener('onDataReceived', (data) => {
console.log('Received:', data.message);
});
// 开始监听
await MyNativePlugin.startListening();
// 移除监听器
await MyNativePlugin.removeAllListeners();
六、异步操作 #
6.1 长时间操作 #
swift
// iOS
@objc func longRunningTask(_ call: CAPPluginCall) {
// 保存call以便后续返回
self.savedCall = call
DispatchQueue.global(qos: .background).async {
// 执行耗时操作
let result = self.performHeavyTask()
DispatchQueue.main.async {
self.savedCall?.resolve([
"result": result
])
self.savedCall = nil
}
}
}
java
// Android
@PluginMethod
public void longRunningTask(PluginCall call) {
// 保存call
bridge.saveCall(call);
new Thread(() -> {
// 执行耗时操作
String result = performHeavyTask();
JSObject response = new JSObject();
response.put("result", result);
call.resolve(response);
bridge.releaseCall(call);
}).start();
}
七、错误处理 #
7.1 统一错误处理 #
swift
// iOS
enum PluginError: Error {
case invalidParameter
case operationFailed
case notAvailable
var message: String {
switch self {
case .invalidParameter: return "Invalid parameter"
case .operationFailed: return "Operation failed"
case .notAvailable: return "Feature not available"
}
}
var code: String {
switch self {
case .invalidParameter: return "INVALID_PARAM"
case .operationFailed: return "OP_FAILED"
case .notAvailable: return "NOT_AVAILABLE"
}
}
}
@objc func someMethod(_ call: CAPPluginCall) {
do {
try performOperation()
call.resolve()
} catch let error as PluginError {
call.reject(error.message, error.code)
} catch {
call.reject(error.localizedDescription)
}
}
java
// Android
public class PluginException extends Exception {
private final String code;
public PluginException(String message, String code) {
super(message);
this.code = code;
}
public String getCode() {
return code;
}
}
@PluginMethod
public void someMethod(PluginCall call) {
try {
performOperation();
call.resolve();
} catch (PluginException e) {
call.reject(e.getMessage(), e.getCode());
} catch (Exception e) {
call.reject(e.getMessage());
}
}
八、总结 #
8.1 开发流程 #
text
1. 创建原生插件类
2. 实现方法
3. 注册插件
4. 创建TypeScript接口
5. 调用测试
8.2 最佳实践 #
- 使用异步操作避免阻塞
- 统一错误处理
- 完善类型定义
- 添加详细注释
8.3 下一步 #
了解原生代码调用后,让我们学习 深度链接!
最后更新:2026-03-28