原生代码调用 #

一、原生代码调用概述 #

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