I have a flutter app that has uses SQFLite to persist data. I'm interested in trying to do an iOS home screen widget, which from what I've been able to gather, has to be built in swiftui. I'm wondering is it possible to access my flutter sqlite database from the native widget in Swiftui?
Update: Trying to use the below suggestion but running into issues. Since the widget extension seems to cause xcode to fail building if I add the appdelegate module as a target to share....I'm attempting to hop it to a swift file call and then sharing that. But I'm running into errors.
My Flutter helper (it's currently just trying to send an integer over from a list count more or less as proof of concept)
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);
}
AppDelegate
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)
}
}
}
Hop File I dubbed 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#>);
}
}
and my widget extension section calling it
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)
}
}
The extension gives me the error on the function call: Editor placeholder in source file.
The widgetSwift gives me errors on the getTasks call: Cannot find 'AppDelegate' in scope Declared closure result '()' is incompatible with contextual type 'Int'
Flutter provides a way to communicate with the native platform code using
MethodChannel
.From the flutter
MethodChannel
documentation (here):MethodChannel
usage to invoke a function on native platform-code from flutter:We create a method channel object in Flutter, iOS, and Android with the same name. The Android and iOS objects will set a method call handler to receive calls from Flutter. The Flutter code can then call invokeMethod to call the handlers on the native objects
Flutter:
Android:
iOS:
Reverse Example – Calling Flutter from Native If you need to call a method defined in Flutter from native code then you call the same methods from earlier, but this time you call
setMethodCallHandler
on the Flutter side andinvokeMethod
on the native side.Flutter:
Android:
iOS:
This article can help you with a more detailed explanation.