Flutter MethodChannel在Android Service的Release APK中无法工作的原因
问题
Debug模式下,从原生Android Service类调用Dart静态函数的代码运行正常,但用flutter build apk生成Release APK安装后,MethodChannel无法工作并报错。相关代码及错误日志如下,请问导致该问题的原因是什么?
Dart代码
void main() { initializeAndroidWidgets(); runApp(MyApp()); } const CHANNEL = "com.app/channel"; // Method channel for Android void initializeAndroidWidgets() { if (Platform.isAndroid) { // Intialize flutter WidgetsFlutterBinding.ensureInitialized(); const MethodChannel channel = MethodChannel(CHANNEL); final CallbackHandle callback = PluginUtilities.getCallbackHandle(rustMethodChannel)!; final handle = callback.toRawHandle(); channel.invokeMethod('initialize', handle); } } void rustMethodChannel() async { // Initialize flutter WidgetsFlutterBinding.ensureInitialized(); PreferenceRepository preferenceRepository = PreferenceRepository(); // Create methodChannel const MethodChannel channel = MethodChannel(CHANNEL); channel.setMethodCallHandler( (call) async { final args = call.arguments; logDebug('on Dart ${call.method}!, args = ${args}'); switch (call.method) { case 'isConnected': return await isConnected(preferenceRepository); case 'startConnect': var result = await startConnect(preferenceRepository); return result; case 'disconnect': return await disconnect(); case 'getTestString': return getTestString(); default: throw UnimplementedError("Unknow: ${call.method}"); } }, ); }
Android Service代码
companion object { private const val TAG = "MyApp"; const val CHANNEL = "com.app/channel" private var channel: MethodChannel? = null; } private fun initializeFlutter() { if (channel == null) { try { FlutterMain.startInitialization(this) FlutterMain.ensureInitializationComplete(this, arrayOf()) val handle = WidgetHelper.getRawHandle(this) if (handle == WidgetHelper.NO_HANDLE) { Log.e(TAG, "Couldn't update widget because there is no handle stored!") return } val callbackInfo = FlutterCallbackInformation.lookupCallbackInformation(handle) val entryPointFunctionName = callbackInfo.callbackName Log.e( TAG, "entryPointFunctionName = ${entryPointFunctionName}, FlutterMain.findAppBundlePath() = ${FlutterMain.findAppBundlePath()}" ) // Instantiate a FlutterEngine. val engine = FlutterEngine(this.applicationContext) val entryPoint = DartExecutor.DartEntrypoint(FlutterMain.findAppBundlePath(), entryPointFunctionName) engine.dartExecutor.executeDartEntrypoint(entryPoint) GeneratedPluginRegistrant.registerWith(engine) channel = MethodChannel(engine.dartExecutor.binaryMessenger, CHANNEL) } catch (e: java.lang.Exception) { e.printStackTrace(); } } } override fun onCreate() { super.onCreate() Log.e(TAG, "Starting service"); initializeFlutter() }
Release模式错误日志
2022-11-10 15:43:54.448 10736-10736/? E/MyApp: entryPointFunctionName = rustMethodChannel, FlutterMain.findAppBundlePath() = flutter_assets 2022-11-10 15:43:54.466 10736-10736/? W/FlutterEngineCxnRegstry: Attempted to register plugin (k1.a@1df89c) but it was already registered with this FlutterEngine (io.flutter.embedding.engine.a@32a92a5). 2022-11-10 15:43:54.466 10736-10736/? W/FlutterEngineCxnRegstry: Attempted to register plugin (u3.a@26ce67a) but it was already registered with this FlutterEngine (io.flutter.embedding.engine.a@32a92a5). 2022-11-10 15:43:54.466 10736-10736/? W/FlutterEngineCxnRegstry: Attempted to register plugin (l1.a@2f37e2b) but it was already registered with this FlutterEngine (io.flutter.embedding.engine.a@32a92a5). 2022-11-10 15:43:54.466 10736-10736/? W/FlutterEngineCxnRegstry: Attempted to register plugin (d2.c@2600288) but it was already registered with this FlutterEngine (io.flutter.embedding.engine.a@32a92a5). 2022-11-10 15:43:54.466 10736-10736/? W/FlutterEngineCxnRegstry: Attempted to register plugin (g0.m@d6b421) but it was already registered with this FlutterEngine (io.flutter.embedding.engine.a@32a92a5). 2022-11-10 15:43:54.466 10736-10736/? W/FlutterEngineCxnRegstry: Attempted to register plugin (e2.b@8d2f046) but it was already registered with this FlutterEngine (io.flutter.embedding.engine.a@32a92a5). 2022-11-10 15:43:54.466 10736-10736/? W/FlutterEngineCxnRegstry: Attempted to register plugin (f2.c@329d207) but it was already registered with this FlutterEngine (io.flutter.embedding.engine.a@32a92a5). 2022-11-10 15:43:54.466 10736-10736/? W/FlutterEngineCxnRegstry: Attempted to register plugin (f0.t@f36bf34) but it was already registered with this FlutterEngine (io.flutter.embedding.engine.a@32a92a5). 2022-11-10 15:43:54.467 10736-10736/? E/MyApp: startWakeLock 2022-11-10 15:43:54.469 10736-10736/? E/MyApp: Starting service 2022-11-10 15:43:54.469 766-774/? E/statsd: Predicate 5980654721335871649 dropping data for dimension key (10)0x2010101->10327[I] (10)0x30000->com.anv3.proxy:wakelock[S] 2022-11-10 15:43:54.477 10736-13937/? E/flutter: [ERROR:flutter/runtime/dart_isolate.cc(668)] Could not resolve main entrypoint function. 2022-11-10 15:43:54.477 10736-13937/? E/flutter: [ERROR:flutter/runtime/dart_isolate.cc(167)] Could not run the run main Dart entrypoint. 2022-11-10 15:43:54.479 10736-13937/? E/flutter: [ERROR:flutter/runtime/runtime_controller.cc(385)] Could not create root isolate. 2022-11-10 15:43:54.479 10736-13937/? E/flutter: [ERROR:flutter/shell/common/shell.cc(604)] Could not launch engine with configuration.
问题原因
核心问题是Release模式下Dart的Tree Shaking(摇树优化)机制把rustMethodChannel函数移除了:
- Debug模式下不会启用摇树优化,编译器会保留所有代码,所以
rustMethodChannel能被正常找到并执行; - Release模式中,Dart编译器会扫描代码,发现
rustMethodChannel没有被Dart代码直接调用,只通过Native侧的CallbackHandle引用,就会将其判定为未使用代码并剔除,导致Flutter Engine启动时找不到该入口函数,抛出Could not resolve main entrypoint function错误。
日志里的插件重复注册警告是次要问题,是Service多次初始化FlutterEngine导致的,但不是崩溃的直接原因。
解决方案
- 阻止摇树优化移除目标函数:在
rustMethodChannel函数上添加@pragma('vm:entry-point')注解,明确告诉编译器这个函数是Native侧的入口点,不能被优化删除。修改后的函数如下:
@pragma('vm:entry-point') void rustMethodChannel() async { // 原函数逻辑保持不变 WidgetsFlutterBinding.ensureInitialized(); PreferenceRepository preferenceRepository = PreferenceRepository(); const MethodChannel channel = MethodChannel(CHANNEL); channel.setMethodCallHandler( (call) async { final args = call.arguments; logDebug('on Dart ${call.method}!, args = ${args}'); switch (call.method) { case 'isConnected': return await isConnected(preferenceRepository); case 'startConnect': var result = await startConnect(preferenceRepository); return result; case 'disconnect': return await disconnect(); case 'getTestString': return getTestString(); default: throw UnimplementedError("Unknow: ${call.method}"); } }, ); }
- 优化FlutterEngine初始化逻辑:确保Service中只初始化一次FlutterEngine,避免插件重复注册的警告。可以通过全局单例或者在Service内部判断Engine是否已创建来实现。
内容的提问来源于stack exchange,提问作者Kingfisher Phuoc
相关产品推荐
相关产品推荐

