uni-app iOS 原生插件开发

核心知识点

1. iOS 开发环境搭建

1.1 开发工具准备

  • Xcode:官方推荐的 iOS 开发 IDE,下载地址:https://developer.apple.com/xcode/
  • Mac OS:iOS 开发必须在 Mac 上进行,推荐使用最新版本的 macOS
  • CocoaPods:iOS 依赖管理工具,用于管理第三方库
  • Apple Developer Account:苹果开发者账号,用于发布应用到 App Store

1.2 环境配置

  • 安装 Xcode:从 App Store 或 Apple 开发者网站下载并安装 Xcode
  • 安装 Command Line Tools:在 Xcode 中安装 Command Line Tools
  • 安装 CocoaPods:使用 RubyGems 安装 CocoaPods
  • 配置开发证书:在 Apple Developer Account 中创建开发证书和 provisioning profile

2. iOS 插件项目结构

2.1 基本目录结构

  • 标准目录结构
    ios/
      ├── Plugin.xcodeproj        # Xcode 项目文件
      ├── Plugin.xcworkspace      # Xcode 工作空间文件(使用 CocoaPods 时生成)
      ├── Plugin/                 # 插件源代码目录
      │   ├── Plugin.h            # 插件头文件
      │   ├── Plugin.m            # 插件实现文件
      │   ├── Module.h            # Module 插件头文件
      │   ├── Module.m            # Module 插件实现文件
      │   ├── Component.h         # Component 插件头文件
      │   └── Component.m         # Component 插件实现文件
      ├── Podfile                 # CocoaPods 配置文件
      └── Pods/                   # CocoaPods 依赖目录(自动生成)

2.2 关键文件说明

  • Plugin.xcodeproj:Xcode 项目文件,包含插件的编译配置
  • Module.h/m:实现 Module 接口,提供 JavaScript 调用的方法
  • Component.h/m:实现 Component 接口,提供自定义 UI 组件
  • Podfile:定义插件的依赖库

3. iOS 插件开发基础

3.1 Module 插件开发

  • 继承 DCUniModule:自定义 Module 类需要继承 DCUniModule
  • 导出方法:使用 DC_EXPORT_METHOD 宏导出方法,供 JavaScript 调用
  • 异步回调:使用 DCUniJSCallback 实现异步回调
  • 上下文获取:通过 weexInstance 获取 WKWebView 实例

3.2 Component 插件开发

  • 继承 DCUniComponent:自定义 Component 类需要继承 DCUniComponent
  • 视图创建:在 viewDidLoad 方法中创建 iOS 视图
  • 属性设置:重写 setAttribute 方法处理组件属性更新
  • 事件处理:使用 fireEvent 方法触发自定义事件

3.3 权限管理

  • 声明权限:在 Info.plist 中声明插件需要的权限
  • 权限申请:使用 requestAuthorization 方法申请权限
  • 权限检查:使用 authorizationStatus 方法检查权限状态

4. 插件打包与集成

4.1 插件打包

  • 构建 Framework:在 Xcode 中构建 Framework 文件
  • 配置 package.json:在插件根目录创建 package.json 文件,配置插件信息
  • 创建 zip 包:将 Framework 文件和 package.json 等文件打包成 zip 文件

4.2 插件集成

  • 本地集成:将插件 zip 包导入到 uni-app 项目中
  • 云端集成:将插件发布到 uni-app 插件市场,然后在项目中引用
  • 配置 manifest.json:在 uni-app 项目的 manifest.json 文件中配置插件

5. 常见问题与解决方案

5.1 依赖冲突

  • 原因:插件依赖的库与 uni-app 或其他插件依赖的库版本冲突
  • 解决方案:在 Podfile 中指定依赖的版本,或使用 pod update 更新依赖

5.2 代码签名

  • 原因:插件的代码签名配置不正确,导致无法构建或运行
  • 解决方案:在 Xcode 中正确配置代码签名,使用有效的开发证书

5.3 版本兼容

  • 原因:不同版本的 iOS 系统 API 不同,导致插件在某些设备上无法正常工作
  • 解决方案:使用 if (@available(iOS 13.0, *)) 检查 iOS 版本,根据版本使用不同的 API

6. Objective-C 与 Swift 混合开发

6.1 Swift 插件开发

  • 创建 Swift 类:继承 DCUniModuleDCUniComponent
  • 导出方法:使用 @objc 标记需要导出的方法
  • 桥接文件:创建 Objective-C 桥接文件,用于 Swift 与 Objective-C 的交互

6.2 混合开发配置

  • 配置 Build Settings:在 Xcode 中配置 Swift 版本和编译选项
  • 创建桥接文件:自动生成或手动创建桥接文件
  • 导入头文件:在 Swift 文件中导入必要的头文件

实用案例分析

案例一:开发一个 iOS 原生 Module 插件

问题描述

需要开发一个 iOS 原生插件,提供获取设备信息的功能。

解决方案

创建一个 iOS Module 插件,实现获取设备信息的方法。

代码示例

  1. 创建插件目录结构
device-info-plugin/
  ├── ios/
  │   ├── DeviceInfoPlugin.xcodeproj
  │   ├── DeviceInfoPlugin/
  │   │   ├── DeviceInfoPlugin.h
  │   │   ├── DeviceInfoPlugin.m
  │   │   ├── DeviceInfoModule.h
  │   │   └── DeviceInfoModule.m
  │   └── Podfile
  └── package.json
  1. 配置 Podfile
platform :ios, '10.0'

target 'DeviceInfoPlugin' do
  # 使用 Swift 版本
  use_frameworks!
  
  # 导入 uni-app 插件开发库
  pod 'DCUniSDK', :podspec => 'https://pod.dcloud.net.cn/UniPlugin/DCUniSDK.podspec'
  
  # 其他依赖
end
  1. 实现 DeviceInfoModule.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "DCUniModule.h"

@interface DeviceInfoModule : DCUniModule

@end
  1. 实现 DeviceInfoModule.m
#import "DeviceInfoModule.h"

@implementation DeviceInfoModule

// 必须添加此宏,才能让 JS 调用到原生方法
DC_EXPORT_METHOD(@selector(getDeviceInfo:))
- (void)getDeviceInfo:(DCUniJSCallback)callback {
    NSMutableDictionary *result = [NSMutableDictionary dictionary];
    
    // 设备型号
    NSString *model = [UIDevice currentDevice].model;
    [result setObject:model forKey:@"model"];
    
    // 设备名称
    NSString *name = [UIDevice currentDevice].name;
    [result setObject:name forKey:@"name"];
    
    // 系统版本
    NSString *systemVersion = [UIDevice currentDevice].systemVersion;
    [result setObject:systemVersion forKey:@"version"];
    
    // 设备标识符
    NSString *identifierForVendor = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    [result setObject:identifierForVendor forKey:@"deviceId"];
    
    // 系统名称
    NSString *systemName = [UIDevice currentDevice].systemName;
    [result setObject:systemName forKey:@"systemName"];
    
    // 电池状态
    UIDeviceBatteryState batteryState = [UIDevice currentDevice].batteryState;
    NSString *batteryStateString = @"unknown";
    switch (batteryState) {
        case UIDeviceBatteryStateUnknown:
            batteryStateString = @"unknown";
            break;
        case UIDeviceBatteryStateUnplugged:
            batteryStateString = @"unplugged";
            break;
        case UIDeviceBatteryStateCharging:
            batteryStateString = @"charging";
            break;
        case UIDeviceBatteryStateFull:
            batteryStateString = @"full";
            break;
    }
    [result setObject:batteryStateString forKey:@"batteryState"];
    
    // 电池电量
    [UIDevice currentDevice].batteryMonitoringEnabled = YES;
    float batteryLevel = [UIDevice currentDevice].batteryLevel;
    [result setObject:@(batteryLevel * 100) forKey:@"batteryLevel"];
    [UIDevice currentDevice].batteryMonitoringEnabled = NO;
    
    if (callback) {
        callback(result);
    }
}

// 必须添加此宏,才能让 JS 调用到原生方法
DC_EXPORT_METHOD(@selector(getAppVersion:))
- (void)getAppVersion:(DCUniJSCallback)callback {
    NSMutableDictionary *result = [NSMutableDictionary dictionary];
    
    NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
    
    // 应用名称
    NSString *appName = [infoDictionary objectForKey:@"CFBundleDisplayName"];
    if (!appName) {
        appName = [infoDictionary objectForKey:@"CFBundleName"];
    }
    [result setObject:appName forKey:@"appName"];
    
    // 应用版本
    NSString *version = [infoDictionary objectForKey:@"CFBundleShortVersionString"];
    [result setObject:version forKey:@"versionName"];
    
    // 构建版本
    NSString *buildVersion = [infoDictionary objectForKey:@"CFBundleVersion"];
    [result setObject:buildVersion forKey:@"versionCode"];
    
    // 包名
    NSString *bundleId = [infoDictionary objectForKey:@"CFBundleIdentifier"];
    [result setObject:bundleId forKey:@"packageName"];
    
    if (callback) {
        callback(result);
    }
}

@end
  1. 配置 package.json
{
  "name": "device-info-plugin",
  "version": "1.0.0",
  "description": "提供设备信息功能的 iOS 原生插件",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "uni-app",
    "plugin",
    "ios",
    "device-info"
  ],
  "author": "example",
  "license": "MIT",
  "uni-app": {
    "plugins": {
      "DeviceInfo": {
        "version": "1.0.0",
        "provider": "com.example.deviceinfo"
      }
    }
  },
  "dcloudPlugins": {
    "ios": {
      "plugins": [
        {
          "type": "module",
          "name": "DeviceInfo",
          "class": "DeviceInfoModule"
        }
      ]
    }
  }
}
  1. 创建 index.js
const deviceInfo = uni.requireNativePlugin('DeviceInfo');

export default {
  getDeviceInfo(callback) {
    deviceInfo.getDeviceInfo(callback);
  },
  getAppVersion(callback) {
    deviceInfo.getAppVersion(callback);
  }
};

案例二:开发一个 iOS 原生 Component 插件

问题描述

需要开发一个 iOS 原生插件,提供一个自定义的开关组件。

解决方案

创建一个 iOS Component 插件,实现一个自定义的开关组件。

代码示例

  1. 创建插件目录结构
switch-plugin/
  ├── ios/
  │   ├── SwitchPlugin.xcodeproj
  │   ├── SwitchPlugin/
  │   │   ├── SwitchPlugin.h
  │   │   ├── SwitchPlugin.m
  │   │   ├── SwitchComponent.h
  │   │   └── SwitchComponent.m
  │   └── Podfile
  └── package.json
  1. 配置 Podfile
platform :ios, '10.0'

target 'SwitchPlugin' do
  # 使用 Swift 版本
  use_frameworks!
  
  # 导入 uni-app 插件开发库
  pod 'DCUniSDK', :podspec => 'https://pod.dcloud.net.cn/UniPlugin/DCUniSDK.podspec'
  
  # 其他依赖
end
  1. 实现 SwitchComponent.h
#import <Foundation/Foundation.h>
#import "DCUniComponent.h"

@interface SwitchComponent : DCUniComponent

@end
  1. 实现 SwitchComponent.m
#import "SwitchComponent.h"

@implementation SwitchComponent {
    UISwitch *_switch;
    BOOL _checked;
    UIColor *_onColor;
    UIColor *_offColor;
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        _checked = NO;
        _onColor = [UIColor colorWithRed:0.0 green:0.478 blue:1.0 alpha:1.0]; // 默认蓝色
        _offColor = [UIColor lightGrayColor];
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 创建 UISwitch
    _switch = [[UISwitch alloc] initWithFrame:CGRectZero];
    _switch.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:_switch];
    
    // 设置约束
    [NSLayoutConstraint activateConstraints:@[
        [_switch.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
        [_switch.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor]
    ]];
    
    // 设置默认值
    [_switch setOn:_checked animated:NO];
    [_switch setOnTintColor:_onColor];
    
    // 添加点击事件
    [_switch addTarget:self action:@selector(switchValueChanged:) forControlEvents:UIControlEventValueChanged];
}

- (void)switchValueChanged:(UISwitch *)sender
{
    _checked = sender.on;
    
    // 触发 change 事件
    if ([self hasEventCallback:@"change"]) {
        [self fireEvent:@"change" params:@{@"value": @(_checked)}];
    }
}

- (void)setAttribute:(NSString *)key value:(id)value
{
    [super setAttribute:key value:value];
    
    if ([key isEqualToString:@"checked"]) {
        if ([value isKindOfClass:[NSNumber class]]) {
            _checked = [value boolValue];
            if (_switch) {
                [_switch setOn:_checked animated:YES];
            }
        }
    } else if ([key isEqualToString:@"color"]) {
        if ([value isKindOfClass:[NSString class]]) {
            UIColor *color = [self colorWithHexString:value];
            _onColor = color;
            if (_switch) {
                [_switch setOnTintColor:_onColor];
            }
        }
    }
}

// 将十六进制颜色字符串转换为 UIColor
- (UIColor *)colorWithHexString:(NSString *)hexString
{
    NSString *cleanString = [hexString stringByReplacingOccurrencesOfString:@"#" withString:@""];
    if ([cleanString length] == 3) {
        cleanString = [NSString stringWithFormat:@"%@%@%@%@%@%@", 
                      [cleanString substringWithRange:NSMakeRange(0, 1)], 
                      [cleanString substringWithRange:NSMakeRange(0, 1)],
                      [cleanString substringWithRange:NSMakeRange(1, 1)], 
                      [cleanString substringWithRange:NSMakeRange(1, 1)],
                      [cleanString substringWithRange:NSMakeRange(2, 1)], 
                      [cleanString substringWithRange:NSMakeRange(2, 1)]];
    }
    
    NSScanner *scanner = [NSScanner scannerWithString:cleanString];
    unsigned int hex;
    if (![scanner scanHexInt:&hex]) return nil;
    
    int r = (hex >> 16) & 0xFF;
    int g = (hex >> 8) & 0xFF;
    int b = (hex) & 0xFF;
    
    return [UIColor colorWithRed:r / 255.0f green:g / 255.0f blue:b / 255.0f alpha:1.0f];
}

@end
  1. 配置 package.json
{
  "name": "switch-plugin",
  "version": "1.0.0",
  "description": "提供自定义开关组件的 iOS 原生插件",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "uni-app",
    "plugin",
    "ios",
    "switch"
  ],
  "author": "example",
  "license": "MIT",
  "uni-app": {
    "plugins": {
      "Switch": {
        "version": "1.0.0",
        "provider": "com.example.switch"
      }
    }
  },
  "dcloudPlugins": {
    "ios": {
      "plugins": [
        {
          "type": "component",
          "name": "switch",
          "class": "SwitchComponent"
        }
      ]
    }
  }
}
  1. 创建 index.js
export default {
  name: 'switch',
  props: {
    checked: {
      type: Boolean,
      default: false
    },
    color: {
      type: String,
      default: '#007AFF'
    }
  },
  emits: ['change']
};

案例三:使用 Swift 开发 iOS 原生插件

问题描述

需要使用 Swift 开发一个 iOS 原生插件,提供获取网络状态的功能。

解决方案

创建一个 Swift 语言的 iOS Module 插件,实现获取网络状态的方法。

代码示例

  1. 创建插件目录结构
network-status-plugin/
  ├── ios/
  │   ├── NetworkStatusPlugin.xcodeproj
  │   ├── NetworkStatusPlugin/
  │   │   ├── NetworkStatusPlugin.h
  │   │   ├── NetworkStatusPlugin.m
  │   │   ├── NetworkStatusModule.swift
  │   │   └── NetworkStatusPlugin-Bridging-Header.h
  │   └── Podfile
  └── package.json
  1. 配置 Podfile
platform :ios, '10.0'

target 'NetworkStatusPlugin' do
  # 使用 Swift 版本
  use_frameworks!
  
  # 导入 uni-app 插件开发库
  pod 'DCUniSDK', :podspec => 'https://pod.dcloud.net.cn/UniPlugin/DCUniSDK.podspec'
  
  # 导入网络状态库
  pod 'ReachabilitySwift'
  
  # 其他依赖
end
  1. 创建桥接文件 NetworkStatusPlugin-Bridging-Header.h
#ifndef NetworkStatusPlugin_Bridging_Header_h
#define NetworkStatusPlugin_Bridging_Header_h

#import "DCUniModule.h"

#endif /* NetworkStatusPlugin_Bridging_Header_h */
  1. 实现 NetworkStatusModule.swift
import Foundation
import Reachability

@objc(NetworkStatusModule)
class NetworkStatusModule: DCUniModule {
    
    private var reachability: Reachability?
    
    @objc func getNetworkStatus(_ callback: DCUniJSCallback?) {
        let status = self.currentNetworkStatus()
        callback?(status)
    }
    
    @objc func startNetworkMonitoring(_ callback: DCUniJSCallback?) {
        do {
            reachability = try Reachability()
            
            NotificationCenter.default.addObserver(self, selector: #selector(networkStatusChanged(_:)), name: .reachabilityChanged, object: reachability)
            
            try reachability?.startNotifier()
            callback?(["status": "success", "message": "开始监控网络状态"])
        } catch {
            callback?(["status": "error", "message": "监控网络状态失败: \(error.localizedDescription)"])
        }
    }
    
    @objc func stopNetworkMonitoring(_ callback: DCUniJSCallback?) {
        reachability?.stopNotifier()
        NotificationCenter.default.removeObserver(self, name: .reachabilityChanged, object: reachability)
        reachability = nil
        callback?(["status": "success", "message": "停止监控网络状态"])
    }
    
    @objc private func networkStatusChanged(_ notification: Notification) {
        let status = self.currentNetworkStatus()
        
        // 触发 networkChange 事件
        if self.hasEventCallback("networkChange") {
            self.fireEvent("networkChange", params: status)
        }
    }
    
    private func currentNetworkStatus() -> [String: Any] {
        var status: [String: Any] = [:]
        
        do {
            let reachability = try Reachability()
            
            switch reachability.connection {
            case .wifi:
                status["type"] = "wifi"
                status["isConnected"] = true
                status["description"] = "WiFi 连接"
            case .cellular:
                status["type"] = "cellular"
                status["isConnected"] = true
                status["description"] = "移动网络连接"
            case .unavailable:
                status["type"] = "none"
                status["isConnected"] = false
                status["description"] = "无网络连接"
            case .none:
                status["type"] = "none"
                status["isConnected"] = false
                status["description"] = "未知网络状态"
            }
        } catch {
            status["type"] = "none"
            status["isConnected"] = false
            status["description"] = "获取网络状态失败"
        }
        
        return status
    }
    
    deinit {
        reachability?.stopNotifier()
        NotificationCenter.default.removeObserver(self)
    }
}

// 必须添加此扩展,才能让 JS 调用到 Swift 方法
extension NetworkStatusModule {
    static func moduleName() -> String {
        return "NetworkStatus"
    }
    
    static func requiresMainQueueSetup() -> Bool {
        return true
    }
}
  1. 配置 package.json
{
  "name": "network-status-plugin",
  "version": "1.0.0",
  "description": "提供网络状态功能的 iOS 原生插件",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "uni-app",
    "plugin",
    "ios",
    "swift",
    "network-status"
  ],
  "author": "example",
  "license": "MIT",
  "uni-app": {
    "plugins": {
      "NetworkStatus": {
        "version": "1.0.0",
        "provider": "com.example.networkstatus"
      }
    }
  },
  "dcloudPlugins": {
    "ios": {
      "plugins": [
        {
          "type": "module",
          "name": "NetworkStatus",
          "class": "NetworkStatusModule"
        }
      ]
    }
  }
}
  1. 创建 index.js
const networkStatus = uni.requireNativePlugin('NetworkStatus');

export default {
  getNetworkStatus(callback) {
    networkStatus.getNetworkStatus(callback);
  },
  startNetworkMonitoring(callback) {
    networkStatus.startNetworkMonitoring(callback);
  },
  stopNetworkMonitoring(callback) {
    networkStatus.stopNetworkMonitoring(callback);
  }
};

案例四:在 uni-app 中使用 iOS 原生插件

问题描述

需要在 uni-app 应用中使用刚才开发的 iOS 原生插件。

解决方案

在 uni-app 项目中引入并使用 iOS 原生插件。

代码示例

  1. 在 manifest.json 中配置插件
{
  "name": "uni-app-demo",
  "version": "1.0.0",
  "description": "uni-app 演示应用",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "uni-app"
  ],
  "author": "example",
  "license": "MIT",
  "dependencies": {
    "@dcloudio/uni-app": "^2.0.0"
  },
  "uni-app": {
    "plugins": {
      "DeviceInfo": {
        "version": "1.0.0",
        "provider": "com.example.deviceinfo"
      },
      "Switch": {
        "version": "1.0.0",
        "provider": "com.example.switch"
      },
      "NetworkStatus": {
        "version": "1.0.0",
        "provider": "com.example.networkstatus"
      }
    }
  }
}
  1. 在页面中使用设备信息插件
<template>
  <view class="device-info-demo">
    <h2>设备信息</h2>
    <button @click="getDeviceInfo">获取设备信息</button>
    <button @click="getAppVersion">获取应用版本</button>
    <view class="result" v-if="deviceInfo">
      <text>设备型号:{{ deviceInfo.model }}</text>
      <text>设备名称:{{ deviceInfo.name }}</text>
      <text>系统版本:{{ deviceInfo.version }}</text>
      <text>设备 ID:{{ deviceInfo.deviceId }}</text>
      <text>系统名称:{{ deviceInfo.systemName }}</text>
      <text>电池状态:{{ deviceInfo.batteryState }}</text>
      <text>电池电量:{{ deviceInfo.batteryLevel }}%</text>
    </view>
    <view class="result" v-if="appVersion">
      <text>应用名称:{{ appVersion.appName }}</text>
      <text>应用版本:{{ appVersion.versionName }}</text>
      <text>构建版本:{{ appVersion.versionCode }}</text>
      <text>包名:{{ appVersion.packageName }}</text>
    </view>
  </view>
</template>

<script>
import deviceInfoPlugin from '@/plugins/device-info-plugin/index.js';

export default {
  data() {
    return {
      deviceInfo: null,
      appVersion: null
    };
  },
  methods: {
    getDeviceInfo() {
      deviceInfoPlugin.getDeviceInfo(res => {
        this.deviceInfo = res;
        console.log('设备信息:', res);
      });
    },
    getAppVersion() {
      deviceInfoPlugin.getAppVersion(res => {
        this.appVersion = res;
        console.log('应用版本:', res);
      });
    }
  }
};
</script>

<style scoped>
.device-info-demo {
  padding: 20rpx;
}

h2 {
  margin-bottom: 20rpx;
  font-size: 36rpx;
  font-weight: bold;
}

button {
  width: 100%;
  padding: 20rpx;
  margin-bottom: 20rpx;
  background-color: #1890ff;
  color: #fff;
  border: none;
  border-radius: 8rpx;
}

.result {
  margin-top: 20rpx;
  padding: 20rpx;
  background-color: #f5f5f5;
  border-radius: 8rpx;
}

.result text {
  display: block;
  margin-bottom: 10rpx;
}
</style>
  1. 在页面中使用开关组件
<template>
  <view class="switch-demo">
    <h2>开关组件</h2>
    <view class="switch-container">
      <text>默认开关:</text>
      <switch 
        :checked="switch1Checked"
        @change="onSwitch1Change"
      />
      <text>{{ switch1Checked ? '开启' : '关闭' }}</text>
    </view>
    <view class="switch-container">
      <text>自定义颜色开关:</text>
      <switch 
        :checked="switch2Checked"
        color="#FF3B30"
        @change="onSwitch2Change"
      />
      <text>{{ switch2Checked ? '开启' : '关闭' }}</text>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      switch1Checked: false,
      switch2Checked: true
    };
  },
  methods: {
    onSwitch1Change(e) {
      this.switch1Checked = e.detail.value;
      console.log('开关1状态:', this.switch1Checked);
    },
    onSwitch2Change(e) {
      this.switch2Checked = e.detail.value;
      console.log('开关2状态:', this.switch2Checked);
    }
  }
};
</script>

<style scoped>
.switch-demo {
  padding: 20rpx;
}

h2 {
  margin-bottom: 20rpx;
  font-size: 36rpx;
  font-weight: bold;
}

.switch-container {
  display: flex;
  align-items: center;
  margin-bottom: 20rpx;
}

.switch-container text {
  margin-right: 20rpx;
}

switch {
  margin-right: 20rpx;
}
</style>
  1. 在页面中使用网络状态插件
<template>
  <view class="network-status-demo">
    <h2>网络状态</h2>
    <button @click="getNetworkStatus">获取网络状态</button>
    <button @click="startMonitoring">开始监控</button>
    <button @click="stopMonitoring">停止监控</button>
    <view class="result" v-if="networkStatus">
      <text>网络类型:{{ networkStatus.type }}</text>
      <text>是否连接:{{ networkStatus.isConnected ? '是' : '否' }}</text>
      <text>描述:{{ networkStatus.description }}</text>
    </view>
    <view class="notification" v-if="networkChange">
      <text>网络状态变化:{{ networkChange.description }}</text>
    </view>
  </view>
</template>

<script>
import networkStatusPlugin from '@/plugins/network-status-plugin/index.js';

export default {
  data() {
    return {
      networkStatus: null,
      networkChange: null
    };
  },
  mounted() {
    // 监听网络状态变化
    this.$on('networkChange', (res) => {
      this.networkChange = res;
      console.log('网络状态变化:', res);
    });
  },
  methods: {
    getNetworkStatus() {
      networkStatusPlugin.getNetworkStatus(res => {
        this.networkStatus = res;
        console.log('网络状态:', res);
      });
    },
    startMonitoring() {
      networkStatusPlugin.startNetworkMonitoring(res => {
        console.log('开始监控:', res);
        uni.showToast({ title: res.message, icon: 'none' });
      });
    },
    stopMonitoring() {
      networkStatusPlugin.stopNetworkMonitoring(res => {
        console.log('停止监控:', res);
        uni.showToast({ title: res.message, icon: 'none' });
      });
    }
  }
};
</script>

<style scoped>
.network-status-demo {
  padding: 20rpx;
}

h2 {
  margin-bottom: 20rpx;
  font-size: 36rpx;
  font-weight: bold;
}

button {
  width: 100%;
  padding: 20rpx;
  margin-bottom: 20rpx;
  background-color: #1890ff;
  color: #fff;
  border: none;
  border-radius: 8rpx;
}

.result {
  margin-top: 20rpx;
  padding: 20rpx;
  background-color: #f5f5f5;
  border-radius: 8rpx;
}

.result text {
  display: block;
  margin-bottom: 10rpx;
}

.notification {
  margin-top: 20rpx;
  padding: 20rpx;
  background-color: #e6f7ff;
  border-radius: 8rpx;
  border-left: 4rpx solid #1890ff;
}
</style>

学习目标

  1. 了解 iOS 开发环境的搭建和配置
  2. 掌握 uni-app iOS 原生插件的目录结构和配置方法
  3. 学会使用 Objective-C 和 Swift 开发 iOS 原生插件
  4. 理解 iOS 原生插件的生命周期和工作原理
  5. 掌握插件的打包、集成和使用方法
  6. 能够解决 iOS 原生插件开发中遇到的常见问题

iOS 原生插件开发最佳实践

  1. 遵循 iOS 开发规范:按照 Apple 推荐的 iOS 开发规范编写代码
  2. 注重代码质量:使用清晰的命名、适当的注释、合理的代码结构
  3. 处理异常情况:合理处理各种异常,提供友好的错误信息
  4. 优化性能:注意内存管理,避免内存泄漏,优化 UI 渲染性能
  5. 测试兼容性:在不同版本的 iOS 设备上测试插件
  6. 提供详细文档:为插件提供清晰的使用文档和示例代码
  7. 使用自动引用计数:合理使用 ARC,避免内存泄漏
  8. 遵循 App Store 审核指南:确保插件符合 App Store 审核要求

总结

iOS 原生插件开发是 uni-app 应用扩展功能的重要手段,通过开发 iOS 原生插件,可以访问 iOS 设备的底层 API,实现更复杂的功能,提升应用性能。

在本教程中,我们学习了 iOS 开发环境的搭建、iOS 插件项目结构、Module 和 Component 插件的开发方法、插件打包与集成等核心知识点。通过三个实用案例,我们了解了如何使用 Objective-C 和 Swift 开发 iOS 原生插件,以及如何在 uni-app 应用中使用这些插件。

要成为一名优秀的 uni-app iOS 原生插件开发者,需要掌握以下技能:

  1. 熟悉 iOS 原生开发,包括 Objective-C、Swift、Xcode 等
  2. 了解 uni-app 插件开发规范和 API
  3. 具备良好的 API 设计能力
  4. 注重代码质量和性能优化
  5. 具备解决问题的能力
  6. 了解 App Store 审核要求

通过不断学习和实践,你可以开发出功能强大、性能优异的 iOS 原生插件,为 uni-app 生态系统做出贡献。

« 上一篇 uni-app Android 原生插件开发 下一篇 » uni-app 鸿蒙原生插件开发