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

iOS扩展Target(如Widget)中Swift调用React Native JS代码方案咨询

解决React Native iOS17交互式Widget触发主App JS代码的方案

因为Widget属于App Extension,和主App是独立进程,RCTEventEmitter依赖主App的React Native运行环境,所以在扩展里无法直接使用。下面是两种可行的跨进程通信方案:

方案一:App Groups + UserDefaults 共享状态

通过App Groups实现主App和Widget的数据共享,结合主App激活时的回调触发JS逻辑:

  1. 配置App Groups
    在Xcode中给主App和Widget扩展添加同一个App Group(Signing & Capabilities → 添加App Groups,输入统一的标识如group.com.yourapp.widget)。

  2. Widget端写入交互事件
    在Widget的交互回调中,把事件信息写入共享的UserDefaults,并标记未处理状态:

    func handleWidgetTap(actionType: String, params: [String: Any]? = nil) {
        guard let sharedDefaults = UserDefaults(suiteName: "group.com.yourapp.widget") else { return }
        
        // 存储事件数据
        if let params = params {
            sharedDefaults.set(try? JSONSerialization.data(withJSONObject: params), forKey: "WidgetEventParams")
        }
        sharedDefaults.set(actionType, forKey: "WidgetEventType")
        sharedDefaults.set(true, forKey: "HasUnprocessedWidgetEvent")
        sharedDefaults.synchronize()
        
        // 唤醒主App(可选,若需立即触发)
        if let url = URL(string: "yourapp://widget-trigger") {
            UIApplication.shared.open(url)
        }
    }
    
  3. 主App端读取并触发JS逻辑
    在AppDelegate的applicationDidBecomeActive或SceneDelegate的sceneDidBecomeActive中检查共享数据,然后通过RN的事件机制发送到JS:

    func applicationDidBecomeActive(_ application: UIApplication) {
        guard let sharedDefaults = UserDefaults(suiteName: "group.com.yourapp.widget"),
              sharedDefaults.bool(forKey: "HasUnprocessedWidgetEvent") else { return }
        
        let actionType = sharedDefaults.string(forKey: "WidgetEventType") ?? ""
        var eventBody: [String: Any] = ["type": actionType]
        
        // 解析参数
        if let paramsData = sharedDefaults.data(forKey: "WidgetEventParams"),
           let params = try? JSONSerialization.jsonObject(with: paramsData) as? [String: Any] {
            eventBody.merge(params) { $1 }
        }
        
        // 发送事件到React Native
        RCTBridge.current()?.eventDispatcher().sendAppEvent(withName: "WidgetInteraction", body: eventBody)
        
        // 清除已处理标记
        sharedDefaults.set(false, forKey: "HasUnprocessedWidgetEvent")
        sharedDefaults.removeObject(forKey: "WidgetEventType")
        sharedDefaults.removeObject(forKey: "WidgetEventParams")
        sharedDefaults.synchronize()
    }
    
  4. RN端监听事件
    在JS代码中监听Native事件,执行对应逻辑:

    import { NativeEventEmitter, NativeModules } from 'react-native';
    import { useEffect } from 'react';
    
    const widgetEventEmitter = new NativeEventEmitter(NativeModules.RCTDeviceEventEmitter);
    const widgetSubscription = widgetEventEmitter.addListener(
      'WidgetInteraction',
      (event) => {
        // 这里执行你的业务逻辑
        console.log('收到Widget交互:', event.type, event);
      }
    );
    
    // 组件卸载时取消订阅
    useEffect(() => {
      return () => widgetSubscription.remove();
    }, []);
    

方案二:自定义URL Scheme 跳转传参

通过自定义URL唤醒主App并携带交互参数,主App解析参数后触发JS逻辑:

  1. 配置自定义URL Scheme
    在Xcode的主AppInfo → URL Types中添加自定义Scheme(如yourapp)。

  2. Widget端触发跳转
    在交互回调中打开带参数的自定义URL:

    func handleWidgetLike(itemId: String) {
        guard let encodedId = itemId.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
              let url = URL(string: "yourapp://widget-action?type=like&id=\(encodedId)") else { return }
        
        UIApplication.shared.open(url, options: [:], completionHandler: nil)
    }
    
  3. 主App端解析URL并触发JS
    在AppDelegate中处理URL跳转:

    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
              let queryItems = components.queryItems else { return false }
        
        // 解析参数
        let eventData = queryItems.reduce(into: [String: String]()) { result, item in
            if let value = item.value {
                result[item.name] = value
            }
        }
        
        // 发送事件到RN
        RCTBridge.current()?.eventDispatcher().sendAppEvent(withName: "WidgetInteraction", body: eventData)
        
        return true
    }
    
  4. RN端监听逻辑同方案一

注意事项

  • 若主App处于后台,openURL会将其唤醒到前台,确保事件能及时处理。
  • App Groups的UserDefaults同步存在微小延迟,结合URL唤醒可提升实时性。
  • 对于iOS17的Widget交互(如按钮、滑块等),需在WidgetConfiguration或Intent的回调中执行上述跨进程逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 05:44:59