Closed sukhcha-in closed 3 years ago
I explained it in other issue
In flutter to send data between the android OS and the dart code you need to work with channels which works over an engine. When the app is starts there is a main engine that created with it, but to make the task work when the flutter app is closed I need to create a different engine which isn't communicate with the main engine. In the end it means that you need to treat the task function like another flutter app, you need to initialize everything again in the task function (in the
executeTask
fun)
In flutter to send data between the android OS and the dart code you need to work with channels which works over an engine. When the app is starts there is a main engine that created with it, but to make the task work when the flutter app is closed I need to create a different engine which isn't communicate with the main engine. In the end it means that you need to treat the task function like another flutter app, you need to initialize everything again in the task function (in the
executeTask
fun)
Okay so it means that we cannot save data to main engine instead executeTask is completely new engine that has it's own state and everything. When we stop task it destroys everything. No data will be kept.
Is there any way to provide initial data from main engine to executeTask engine?
get_storage
plugin works fine but I want to use headless webview inside foreground service.
When app is running in background it works fine. But when main app is terminated there is MissingPluginException
.
E/flutter ( 9122): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: MissingPluginException(No implementation found for method createHeadlessWebView on channel com.pichillilorenzo/flutter_headless_inappwebview)
E/flutter ( 9122): #0 MethodChannel._invokeMethod
package:flutter/…/services/platform_channel.dart:157
E/flutter ( 9122): <asynchronous suspension>
E/flutter ( 9122): #1 MethodChannel.invokeMethod
package:flutter/…/services/platform_channel.dart:332
E/flutter ( 9122): #2 HeadlessInAppWebView.run
package:flutter_inappwebview/src/headless_in_app_webview.dart:117
E/flutter ( 9122): #3 periodicTaskFun.<anonymous closure>
package:app/screens/fgservice.dart:120
E/flutter ( 9122): #4 periodicTaskFun.<anonymous closure>
package:app/screens/fgservice.dart:90
E/flutter ( 9122): #5 FlutterForegroundServicePlugin.executeTask.<anonymous closure>
package:flutter_foreground_service_plugin/flutter_foreground_service_plugin.dart:184
E/flutter ( 9122): #6 MethodChannel._handleAsMethodCall
package:flutter/…/services/platform_channel.dart:430
E/flutter ( 9122): #7 MethodChannel.setMethodCallHandler.<anonymous closure>
package:flutter/…/services/platform_channel.dart:383
E/flutter ( 9122): #8 _DefaultBinaryMessenger.handlePlatformMessage
package:flutter/…/services/binding.dart:283
E/flutter ( 9122): #9 _invoke3.<anonymous closure> (dart:ui/hooks.dart:280:15)
E/flutter ( 9122): #10 _rootRun (dart:async/zone.dart:1190:13)
E/flutter ( 9122): #11 _CustomZone.run (dart:async/zone.dart:1093:19)
E/flutter ( 9122): #12 _CustomZone.runGuarded (dart:async/zone.dart:997:7)
E/flutter ( 9122): #13 _invoke3 (dart:ui/hooks.dart:279:10)
E/flutter ( 9122): #14 _dispatchPlatformMessage (dart:ui/hooks.dart:154:5)
Any way to handle this?
In flutter to send data between the android OS and the dart code you need to work with channels which works over an engine. When the app is starts there is a main engine that created with it, but to make the task work when the flutter app is closed I need to create a different engine which isn't communicate with the main engine. In the end it means that you need to treat the task function like another flutter app, you need to initialize everything again in the task function (in the
executeTask
fun)Okay so it means that we cannot save data to main engine instead executeTask is completely new engine that has it's own state and everything. When we stop task it destroys everything. No data will be kept.
Is there any way to provide initial data from main engine to executeTask engine?
I am pretty sure there is a way to send some arguments but it will be basic types numeric, decimal ans string I don't think there is a good way to send something else
get_storage
plugin works fine but I want to use headless webview inside foreground service.When app is running in background it works fine. But when main app is terminated there is
MissingPluginException
.E/flutter ( 9122): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: MissingPluginException(No implementation found for method createHeadlessWebView on channel com.pichillilorenzo/flutter_headless_inappwebview) E/flutter ( 9122): #0 MethodChannel._invokeMethod package:flutter/…/services/platform_channel.dart:157 E/flutter ( 9122): <asynchronous suspension> E/flutter ( 9122): #1 MethodChannel.invokeMethod package:flutter/…/services/platform_channel.dart:332 E/flutter ( 9122): #2 HeadlessInAppWebView.run package:flutter_inappwebview/src/headless_in_app_webview.dart:117 E/flutter ( 9122): #3 periodicTaskFun.<anonymous closure> package:app/screens/fgservice.dart:120 E/flutter ( 9122): #4 periodicTaskFun.<anonymous closure> package:app/screens/fgservice.dart:90 E/flutter ( 9122): #5 FlutterForegroundServicePlugin.executeTask.<anonymous closure> package:flutter_foreground_service_plugin/flutter_foreground_service_plugin.dart:184 E/flutter ( 9122): #6 MethodChannel._handleAsMethodCall package:flutter/…/services/platform_channel.dart:430 E/flutter ( 9122): #7 MethodChannel.setMethodCallHandler.<anonymous closure> package:flutter/…/services/platform_channel.dart:383 E/flutter ( 9122): #8 _DefaultBinaryMessenger.handlePlatformMessage package:flutter/…/services/binding.dart:283 E/flutter ( 9122): #9 _invoke3.<anonymous closure> (dart:ui/hooks.dart:280:15) E/flutter ( 9122): #10 _rootRun (dart:async/zone.dart:1190:13) E/flutter ( 9122): #11 _CustomZone.run (dart:async/zone.dart:1093:19) E/flutter ( 9122): #12 _CustomZone.runGuarded (dart:async/zone.dart:997:7) E/flutter ( 9122): #13 _invoke3 (dart:ui/hooks.dart:279:10) E/flutter ( 9122): #14 _dispatchPlatformMessage (dart:ui/hooks.dart:154:5)
Any way to handle this?
Can you copy your task fun to here
Can you copy your task fun to here
import 'package:flutter_inappwebview/flutter_inappwebview.dart'; //https://pub.dev/packages/flutter_inappwebview
import 'package:get_storage/get_storage.dart'; //https://pub.dev/packages/get_storage
void periodicTaskFun() {
FlutterForegroundServicePlugin.executeTask(() async {
//headless webview which doesn't work when app is terminated
HeadlessInAppWebView headlessWebView = HeadlessInAppWebView(
initialUrl: 'https://xxx.ngrok.io/api/test',
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
debuggingEnabled: true,
),
),
onWebViewCreated: (controller) {
print('HeadlessInAppWebView created!');
},
onConsoleMessage: (controller, consoleMessage) {
print("CONSOLE MESSAGE: " + consoleMessage.message);
},
onLoadStart: (controller, url) async {
print("onLoadStart $url");
},
onLoadStop: (controller, url) async {
print("onLoadStop $url");
},
onUpdateVisitedHistory: (InAppWebViewController controller, String url,
bool androidIsReload) {
print("onUpdateVisitedHistory $url");
},
);
headlessWebView.run();
//end headless webview
// When service started
if (GetStorage().read('started_at') == null) {
GetStorage().write('started_at', DateTime.now().toString());
} else {
print(GetStorage().read('started_at'));
}
// save times service ran
int ran = GetStorage().read('ran') ?? 0;
GetStorage().write('ran', ran + 1);
await FlutterForegroundServicePlugin.refreshForegroundServiceContent(
notificationContent: NotificationContent(
iconName: 'ic_launcher',
titleText: 'Task ran',
bodyText: '${DateTime.now()}',
subText: '${ran.toString()} times',
color: Colors.blue,
),
);
// headlessWebView.dispose();
print('Task ran: ${ran.toString()} times');
});
}
@sukhcha-in I will check this and let you know if I find a solution
@sukhcha-in I created a new project and I copied your code and everything runs,
try to do a clean your build of your project and launch it again flutter clean
@sukhcha-in I created a new project and I copied your code and everything runs,
try to do a clean your build of your project and launch it again
flutter clean
Does it work when app is terminated? It works when app is in foreground. It works when app is in background. It doesn't work when app is terminated but foreground service is running.
@sukhcha-in I created a new project and I copied your code and everything runs, try to do a clean your build of your project and launch it again
flutter clean
Does it work when app is terminated? It works when app is in foreground. It works when app is in background. It doesn't work when app is terminated but foreground service is running.
I forgot about that part. ya it doesn't work when the app is closed.
I will look for a solution
@sukhcha-in OK So from what I see the problem isn't in my plugin it is in the webview plugin
this is the error log:
2021-01-25 00:19:50.340 15794-15794/com.example.flutter_application_1 E/MethodChannel#com.pichillilorenzo/flutter_headless_inappwebview: Failed to handle method call
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.content.Context.getSystemService(java.lang.String)' on a null object reference
at com.pichillilorenzo.flutter_inappwebview.InAppWebView.FlutterWebView.<init>(FlutterWebView.java:49)
at com.pichillilorenzo.flutter_inappwebview.HeadlessInAppWebViewManager.createHeadlessWebView(HeadlessInAppWebViewManager.java:74)
at com.pichillilorenzo.flutter_inappwebview.HeadlessInAppWebViewManager.onMethodCall(HeadlessInAppWebViewManager.java:59)
at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:233)
at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:85)
at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:692)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:336)
at android.os.Looper.loop(Looper.java:174)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
this is the problematic code line:
DisplayManager displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
as you can see the exception comes from the FlutterWebView
class
it try to get the DisplayManager
of the app but the context
is null
so it throws an exception
from what I see the context
of the FlutterWebView
is bind to the activity of the app and because the app is dead there is no activity therefore there is no context
I hope it understandable and sorry for bad English
Is there any way to use other plugins inside foreground service?
I'm trying to save how many times the service ran, but unfortunately
get_storage
plugin doesn't work.I've also tried
foreground_service
plugin. Same issue with that one. Is there some kind of limitations?