flutter - 将数据从 Flutter 传递到 SwiftUI 主屏幕 WidgetExtension?访问 SQLite DB 本身还是使用方法通道?
问题描述
我有一个使用 SQFLite 来持久化数据的颤振应用程序。我有兴趣尝试做一个 iOS 主屏幕小部件,据我所知,它必须在 swiftui 中构建。我想知道是否可以从 Swiftui 中的本机小部件访问我的颤振 sqlite 数据库?
更新:尝试使用以下建议但遇到问题。由于如果我将 appdelegate 模块添加为共享目标,小部件扩展似乎会导致 xcode 构建失败......我试图将它跳到一个快速文件调用然后共享它。但我遇到了错误。
我的 Flutter 助手(它目前只是试图从列表中发送一个整数或多或少作为概念证明)
import 'package:flutter/services.dart';
import 'dart:async';
import 'db.dart';
final channelName = 'widgetDataCheckItOff';
Future<void> _handleMethod(MethodCall call) async {
final String utterance = call.arguments;
switch(call.method) {
case "getDataFromFlutter":
var db = new DB();
dynamic result = await db.widgetQuery();
return result;
}
final methodChannel = MethodChannel(channelName);
methodChannel.setMethodCallHandler(_handleMethod);
}
应用委托
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
var controller : FlutterViewController!;
var widgetDataCheckItOff : FlutterMethodChannel!;
class func shared() -> AppDelegate
{
return UIApplication.shared.delegate as! AppDelegate
}
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
controller = window?.rootViewController as? FlutterViewController;
widgetDataCheckItOff = FlutterMethodChannel (
name : "widgetDataCheckItOff",
binaryMessenger : controller as! FlutterBinaryMessenger
)
GeneratedPluginRegistrant.register(with: self)
if #available(iOS 10.0, *) { UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate }
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
@available(iOS 9.0, *)
override func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
let controller = window.rootViewController as? FlutterViewController
let channel = FlutterMethodChannel(name: "plugins.flutter.io/quick_actions", binaryMessenger: controller! as! FlutterBinaryMessenger)
channel.invokeMethod("launch", arguments: shortcutItem.type)
}
public func getTasks ( args: String, completion:@escaping (Int) -> Int) {
var x = -1
widgetDataCheckItOff.setMethodCallHandler { (call : FlutterMethodCall, result: @escaping FlutterResult) in
// print("set method call handler")
if(call.method == "getDataFromFlutter") {
self.widgetDataCheckItOff.invokeMethod ("getDataFromFlutter", arguments: args, result: {(r:Any?) -> () in
x=r as! Int
});
}
else{
result(FlutterMethodNotImplemented)
x = -1// to handle undeclared methods
}
let result = x
completion(result)
}
}
}
跳文件我称为widgetSwift
import Foundation
@objc class WidgetData: NSObject{
public func getWidgetData(result: Int)-> Int {
var x = -1
let a = UIApplication.shared.delegate as! AppDelegate
a.getTasks(args: "getDataFromFlutter", completion: {(result) -> Int in
x = result
})
return x
// let x = AppDelegate.getTasks(<#T##self: AppDelegate##AppDelegate#>);
}
}
和我的小部件扩展部分调用它
struct widget_extension_widgetEntryView : View {
var entry: Provider.Entry
var body: some View {
let w = WidgetData()
let x: Int = w.getWidgetData(result: <#Int#>)
let str = "Today's Tasks: \(x)"
Text("", tableName: str)
}
}
扩展给我函数调用的错误:源文件中的编辑器占位符。
widgetSwift 在 getTasks 调用时给了我错误:在范围内找不到“AppDelegate”声明的闭包结果“()”与上下文类型“Int”不兼容
解决方案
Flutter 提供了一种使用MethodChannel
.
从颤振MethodChannel
文档(这里):
Flutter 使用灵活的系统,允许您调用特定于平台的 API,无论是 Android 上的 Kotlin 或 Java 代码,还是 iOS 上的 Swift 或 Objective-C 代码。
注意:如果需要,方法调用也可以反向发送,平台充当 Dart 中实现的方法的客户端。一个具体的例子是quick_actions插件。
MethodChannel
从颤振调用本机平台代码上的函数的用法:
我们在 Flutter、iOS 和 Android 中创建一个同名的方法通道对象。Android 和 iOS 对象将设置一个方法调用处理程序来接收来自 Flutter 的调用。然后 Flutter 代码可以调用 invokeMethod 来调用原生对象上的处理程序
扑:
static final channelName = 'com.example.widget/database';
final methodChannel = MethodChannel(channelName);
await this.methodChannel.invokeMethod("getDataFromDatabase");
安卓:
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodChannel;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "com.example.widget/database";
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
if (call.method.equals("getDataFromDatabase")) {
//TODO: Perform method to query database here
String data;
if (data != null) {
result.success(data);
} else {
result.error("UNAVAILABLE", "Data not available", null);
}
} else {
result.notImplemented();
}
}
);
}
}
IOS:
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let batteryChannel = FlutterMethodChannel(name: "com.example.widget/database",
binaryMessenger: controller.binaryMessenger)
batteryChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
// Note: this method is invoked on the UI thread.
guard call.method == "getDataFromDatabase" else {
result(FlutterMethodNotImplemented)
return
}
//TODO: Perform method to query database here
let data;
if data == nil {
result(FlutterError(code: "UNAVAILABLE",
message: "Data not available",
details: nil))
} else {
result(data)
}
})
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
逆向示例——从 Native 调用 Flutter
如果您需要从 Native 代码调用 Flutter 中定义的方法,那么您调用之前的相同方法,但这次您setMethodCallHandler
在 Flutter 端和invokeMethod
Native 端调用。
扑:
final channelName = 'dataFromFlutterChannel';
final methodChannel = MethodChannel(channelName);
methodChannel.setMethodCallHandler(this._handleMethod);
Future<void> _handleMethod(MethodCall call) async {
final String utterance = call.arguments;
switch(call.method) {
case "getDataFromFlutter":
//TODO: Query database here and return the data to native side
}
}
安卓:
val channelName = 'dataFromFlutterChannel'
val methodChannel = MethodChannel(flutterView, channelName)
methodChannel.invokeMethod("getDataFromFlutter", utterance)
IOS:
let rootViewController : FlutterViewController = window?.rootViewController as! FlutterViewController
let channelName = "dataFromFlutterChannel"
let methodChannel = FlutterEventChannel(name: channelName, binaryMessenger: rootViewController)
methodChannel.invokeMethod("getDataFromFlutter", utterance)
本文可以帮助您进行更详细的解释。
推荐阅读
- cron - 以编程方式完成作业后如何停止cron作业
- r - 新手麻烦为报告构建脚本
- java - SQLite 聚合查询
- java - Java中的HTTPS与HTTP
- javascript - 在此代码中,javascript 验证不起作用
- c++ - 未定义对 std::type_info::operator==(std::type_info const&) 的引用 const: 0509-036 无法使用 GCC4.8.5 在 AIX7.1 上加载程序
- arrays - 需要帮助重新排列数据库
- javascript - 如果用作类扩展器,则重新导出 es6 类模块不起作用
- python - AttributeError:“FreqDist”对象没有属性“viewitems”
- apache-kafka - org.apache.kafka.clients.consumer.RetriableCommitFailedException:偏移提交失败,出现可重试异常