You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Expo React Native创建iOS锁屏小组件?

使用Expo React Native实现iOS锁屏小组件

明确说明:Expo官方目前没有直接支持锁屏小组件的API,必须通过原生代码集成SwiftUI Widget,再和你的Expo应用打通数据交互。以下是具体步骤和代码示例:

1. 配置EAS构建环境

确保你的Expo项目已启用EAS(用于自定义原生代码):

eas build:configure

2. 添加SwiftUI Widget目标

在Xcode中打开项目的iOS工程(路径为ios/YourProjectName.xcworkspace):

  • 点击菜单栏 File > New > Target
  • 选择 Widget Extension,命名为LockScreenWidget,可选勾选"Include Configuration Intent"(用于动态配置)
  • 确认激活目标,Xcode会自动生成Widget基础代码

3. 编写锁屏适配的SwiftUI代码

替换自动生成的LockScreenWidget.swift内容,适配锁屏的systemSmall尺寸:

import WidgetKit
import SwiftUI
import Intents

struct Provider: IntentTimelineProvider {
    func placeholder(in context: Context) -> SimpleEntry {
        SimpleEntry(date: Date(), configuration: ConfigurationIntent(), widgetData: "默认数据")
    }

    func getSnapshot(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) {
        let entry = SimpleEntry(date: Date(), configuration: configuration, widgetData: "快照数据")
        completion(entry)
    }

    func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        var entries: [SimpleEntry] = []
        
        // 从共享组UserDefaults读取React Native传递的数据
        let sharedData = UserDefaults(suiteName: "group.com.yourapp.bundleid")?.string(forKey: "widgetData") ?? "无数据"

        // 生成每15分钟刷新一次的时间线
        let currentDate = Date()
        for minuteOffset in 0 ..< 4 {
            let entryDate = Calendar.current.date(byAdding: .minute, value: minuteOffset * 15, to: currentDate)!
            let entry = SimpleEntry(date: entryDate, configuration: configuration, widgetData: sharedData)
            entries.append(entry)
        }

        let timeline = Timeline(entries: entries, policy: .atEnd)
        completion(timeline)
    }
}

struct SimpleEntry: TimelineEntry {
    let date: Date
    let configuration: ConfigurationIntent
    let widgetData: String
}

struct LockScreenWidgetEntryView : View {
    var entry: Provider.Entry

    var body: some View {
        VStack {
            Text("锁屏组件")
                .font(.headline)
            Text(entry.widgetData)
                .font(.caption)
        }
        .padding()
        .background(Color.gray.opacity(0.1))
    }
}

struct LockScreenWidget: Widget {
    let kind: String = "LockScreenWidget"

    var body: some WidgetConfiguration {
        IntentConfiguration(kind: kind, intent: ConfigurationIntent.self, provider: Provider()) { entry in
            LockScreenWidgetEntryView(entry: entry)
        }
        .configurationDisplayName("我的锁屏组件")
        .description("显示来自App的动态数据")
        .supportedFamilies([.systemSmall]) // 指定仅支持锁屏小尺寸
    }
}

struct LockScreenWidget_Previews: PreviewProvider {
    static var previews: some View {
        LockScreenWidgetEntryView(entry: SimpleEntry(date: Date(), configuration: ConfigurationIntent(), widgetData: "预览数据"))
            .previewContext(WidgetPreviewContext(family: .systemSmall))
    }
}

4. 配置App Groups实现数据共享

为了让React Native应用和Widget互通数据,需要配置App Groups:

  • 选择主App目标,进入 Signing & Capabilities,点击+ Capability添加App Groups
  • 创建组ID,比如group.com.yourapp.bundleid
  • 给Widget目标添加相同的App Groups配置

5. 在React Native中传递数据到Widget

使用expo-modules-core编写自定义模块,实现数据写入和Widget刷新:

先安装依赖:

npx expo install expo-modules-core

React Native侧代码:

import { Platform } from 'react-native';
import { NativeModules } from 'react-native';

// 向Widget写入数据并触发刷新
export const updateWidgetData = async (data) => {
  if (Platform.OS !== 'ios') return;
  try {
    await NativeModules.ExpoWidgetData.setSharedData('widgetData', data, 'group.com.yourapp.bundleid');
  } catch (err) {
    console.error('更新Widget数据失败:', err);
  }
};

对应的Swift原生模块(创建ExpoWidgetData.swift):

import ExpoModulesCore

public class ExpoWidgetData: Module {
  public func definition() -> ModuleDefinition {
    Name("ExpoWidgetData")
    
    AsyncFunction("setSharedData") { (key: String, value: String, groupId: String) in
      let userDefaults = UserDefaults(suiteName: groupId)
      userDefaults?.set(value, forKey: key)
      // 通知Widget刷新时间线
      WidgetCenter.shared.reloadAllTimelines()
    }
  }
}

6. 构建测试

使用EAS构建iOS包并安装到测试设备:

eas build --platform ios

安装完成后,进入锁屏编辑模式,添加你创建的小组件即可测试效果。

内容的提问来源于stack exchange,提问作者Dna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 19:52:19