V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lixyz
V2EX  ›  Flutter

Anroid 项目集成 Flutter module, Flutter 页面通过 MethodChannel 调用 Android 中的方法,抛 MissingPluginException

  •  
  •   lixyz · 2020-06-11 05:08:35 +08:00 · 2934 次点击
    这是一个创建于 1632 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在学习 Flutter,被一个问题折腾了好几天了,问题简化如下:

    Flutter 版本是 v1.17.0

    现有 Android 工程,里面有两个 Activity:

    1. MainActivity,该 Activity 中有一个按钮
    2. NativeActivity 。

    然后又按照官方文档集成了 Flutter module,里面有页面 FlutterRoute,FlutterRoute 中有一个按钮。

    现在操作逻辑如下: 点击 MainActivity 中的按钮,跳转到 Flutter 页面,然后点击 FlutterRoute 中的按钮,再跳转到 NativeActivity 。

    现在 MainActivity 代码如下:

    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    
    import androidx.annotation.NonNull;
    
    import io.flutter.embedding.android.FlutterActivity;
    import io.flutter.embedding.engine.FlutterEngine;
    import io.flutter.plugin.common.MethodCall;
    import io.flutter.plugin.common.MethodChannel;
    import io.flutter.plugins.GeneratedPluginRegistrant;
    
    
    public class MainActivity extends FlutterActivity implements View.OnClickListener, MethodChannel.MethodCallHandler {
    
        private Button button;
        private static final String CHANNEL_NAME = "TEST_CHANNEL_NAME";
        private MethodChannel channel;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            button = findViewById(R.id.button);
            button.setOnClickListener(this);
    
    
        }
    
        @Override
        public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
            super.configureFlutterEngine(flutterEngine);
            GeneratedPluginRegistrant.registerWith(flutterEngine);
            channel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL_NAME);
            channel.setMethodCallHandler(this);
        }
    
        @Override
        public void onClick(View v) {
            startActivity(
                    FlutterActivity.withNewEngine().build(this)
            );
        }
    
    
        @Override
        public void onMethodCall(@NonNull MethodCall methodCall, @NonNull MethodChannel.Result result) {
            if ("startNativeActivity".equals(methodCall.method)) {
                Intent intent = new Intent(MainActivity.this, NativeActivity.class);
                startActivity(intent);
            }
        }
    }
    

    Flutter 代码如下:

    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    
    void main(){
      runApp(
          MaterialApp(
            routes: {
              "/":(BuildContext context)=>FlutterRoute(),
            },
            initialRoute: "/",
          )
      );
    }
    
    class FlutterRoute extends StatefulWidget {
      FlutterRouteState createState() {
        return FlutterRouteState();
      }
    }
    
    class FlutterRouteState extends State<FlutterRoute> {
    
      static const channel = MethodChannel("TEST_CHANNEL_NAME");
    
      Future<void> startNativeActivity() async{
        await channel.invokeMethod("startNativeActivity");
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("Flutter 页面"),
          ),
          body: Container(
            color: Colors.lightGreenAccent,
            child: Center(
              child: Column(
                children: <Widget>[
                  Text("Flutter 页面"),
                  MaterialButton(
                    color: Colors.redAccent,
                    child: Text("跳转到原生 Activity"),
                    onPressed: () {
                      startNativeActivity();
                    },
                  ),
                ],
              ),
            ),
          ),
        );
      }
    }
    

    在 MainActivity 中点击按钮,可以跳转到 FlutterRoute,但是在 FlutterRoute 中点击按钮跳转到 NativeActivity 的时候却抛出:

    E/flutter: [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: MissingPluginException(No implementation found for method startNativeActivity on channel TEST_CHANNEL_NAME)
        #0      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:154:7)
        <asynchronous suspension>
        #1      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:329:12)
        #2      FlutterRouteState.startNativeActivity (package:fluttermodule/main.dart:27:19)
        #3      FlutterRouteState.build.<anonymous closure> (package:fluttermodule/main.dart:46:19)
        #4      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:779:19)
        #5      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:862:36)
        #6      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
        #7      TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:504:11)
        #8      BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:282:5)
        ......
    

    究竟是哪里出了问题啊,折腾好几天了,始终不行,难道 MethodChannel 不是这么用的吗?

    百度谷歌官方 githubStackOverflow 搜了个遍。。。

    实在没辙了,求点醒求指教,感谢

    6 条回复    2020-07-12 23:22:41 +08:00
    mxT52CRuqR6o5
        1
    mxT52CRuqR6o5  
       2020-06-11 05:53:03 +08:00 via Android
    lixyz
        2
    lixyz  
    OP
       2020-06-11 16:03:01 +08:00
    @mxT52CRuqR6o5 大哥啊,我就是参照那个文档改的啊,可就是不行啊

    在 Flutter 工程中,使用 MethodChannel 是可以获取宿主原生系统的信息的

    但是把 Flutter 作为 module 添加到 Android 工程中,MethodChannel 就有问题了
    mxT52CRuqR6o5
        3
    mxT52CRuqR6o5  
       2020-06-11 21:57:18 +08:00
    官方教程的 demo 要在 flutter 侧 invokeMethod('getBatteryLevel'),然后在 native 侧的 MainActivity 有实现 getBatteryLevel
    现在你要 invokeMethod('startNativeActivity'),然而在你的 native 侧的中并没有实现 startNativeActivity
    所以才会提示 [No implementation found for method startNativeActivity on channel TEST_CHANNEL_NAME]
    lixyz
        4
    lixyz  
    OP
       2020-06-11 23:25:36 +08:00
    @mxT52CRuqR6o5
    在 Native 侧实现了啊。。。
    ```java

    ...

    @Override
    public void onMethodCall(@NonNull MethodCall methodCall, @NonNull MethodChannel.Result result) {
    if ("startNativeActivity".equals(methodCall.method)) {
    Intent intent = new Intent(MainActivity.this, NativeActivity.class);
    startActivity(intent);
    }
    }
    ```
    mxT52CRuqR6o5
        5
    mxT52CRuqR6o5  
       2020-06-12 02:46:13 +08:00 via Android
    @lixyz 用浏览器搜索功能在我发的那个网页里搜 getBatteryLevel,你看官方是怎么实现的,相关的代码是写在了什么位置
    kelvinluo1112
        6
    kelvinluo1112  
       2020-07-12 23:22:41 +08:00 via Android
    你没有调用 result 对象的 success 方法啊
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5928 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 02:28 · PVG 10:28 · LAX 18:28 · JFK 21:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.