本地环境如下:

Flutter 2.2.0-10.1.pre • channel beta

Dart 2.13.0

之前创建了一个Flutter项目,项目中需要判定手机蓝牙是否打开,这时候就需要调用原生代码,但是在网上查看资料时候发现很多资料过时或不能用,原因应该是电脑上的Flutter版本比较高,搞定之后就记录一下。

项目创建时选择了支持Kotlin及Swift,所有项目整体的结构可能不太一样

Flutter端代码

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class BeControlPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text('被控制端'),
      ),
      body: TestWidget()
    );
  }
}

class TestWidget extends StatefulWidget {
  @override
  _TestIosWidgetState createState() => _TestIosWidgetState();
}

class _TestIosWidgetState extends State<TestWidget> {

  // 调用原生相关代码
  Future runMethod() async{
    // 自定义的通道且名字为test,在原生中会使用到,只要对的上通道名称才可调用相关方法
    const platform = const MethodChannel('test');
    var result;
    try{
      // Flutter提供三种方法与原生交互
      // MethodChannel    用于 Flutter 与 原生平台之间函数的互相调用
      // BasicMessageChannel    它传递的是字节数组,使用时自定义编解码器
      // EventChannel    用于 Flutter 与 原生平台之间事件的通信
      // 这里使用的是MethodChannel方式
      result = await platform.invokeMethod('isHavePermission');
      return Future.value(result);
    } on PlatformException catch (e){
      return Future.error(e.toString());
    }
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: FlatButton(
        onPressed: () async{
          // 点击按钮后通过原生方法获取到返回值
          var futureValue = await runMethod();
          // 拿到返回值后弹出框显示返回值
          return showDialog(context: context, builder: (context){
            return AlertDialog(
              content: Text(
                futureValue,
                textAlign: TextAlign.center,
              ),
            );
          });
        },
        child:
          Text(
              '信我,得永生',
              style: TextStyle(fontSize: 18.0),
          ),
        color: Colors.red,
        textColor: Colors.white,
        ),
    );
  }
}

iOS端

  1. 新建OC文件,命名为FlutterNativePlugin,继承与NSObject<FlutterPlugin>,.h文件如下:

    #import <Foundation/Foundation.h>
    #import <Flutter/Flutter.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface FlutterNativePlugin : NSObject<FlutterPlugin>
    
    @end
    
    NS_ASSUME_NONNULL_END
.m文件如下:
   #import "FlutterNativePlugin.h"
   
   @implementation FlutterNativePlugin
   
   + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
   FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:@"test" binaryMessenger:[registrar messenger]];
   FlutterNativePlugin *instance = [[FlutterNativePlugin alloc]init];
   [registrar addMethodCallDelegate:instance channel:channel];
   }
   
   - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
   if ([call.method isEqualToString:@"isHavePermission"]) {
       result(@"有了-iOS");
   }else {
       result(FlutterMethodNotImplemented);
   }
   }
   
   @end
  1. 在AppDelegate里注册工具类

    import UIKit
    import Flutter
    
    @UIApplicationMain
    @objc class AppDelegate: FlutterAppDelegate {
      override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
        GeneratedPluginRegistrant.register(with: self)
        FlutterNativePlugin.register(with: self.registrar(forPlugin: "FlutterNativePlugin") as! FlutterPluginRegistrar)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }
    }

Android端

Android端多说一点,由于在Flutter1.12后Flutter官方舍弃了io.flutter.app.FlutterActivity,所以网上很多代码就可能无法使用了

  1. 新建后的Flutter项目Android目录各种标红

这时候鼠标随便打开Android目录下的某一个文件,点击代码编辑区上方的

使用Android打开会下载一些依赖,并且也无标红了

  1. 编写MainActivity代码:

    很多文章中写的,如https://www.jianshu.com/p/310c28abc9f3文中的代码:

    他导入的是io.flutter.app.FlutterActivity头文件,导入此文件这样写不会有问题,而且相关代码写在onCreate方法中,但是在Flutter1.12后此方法废弃,新建的项目均导入的是io.flutter.embedding.android.FlutterActivity头文件,详情见官方文档,所以,如果你的Flutter版本大于1.12,则正确的代码为:

    package com.imowfms.flutter_app
    
    import io.flutter.embedding.android.FlutterActivity
    import io.flutter.embedding.engine.FlutterEngine
    import io.flutter.plugin.common.MethodChannel
    import io.flutter.plugins.GeneratedPluginRegistrant
    
    class MainActivity: FlutterActivity() {
        private val channel = "test"
    
        override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
            GeneratedPluginRegistrant.registerWith(flutterEngine)
    
            MethodChannel(flutterEngine.dartExecutor.binaryMessenger,channel)
                    .setMethodCallHandler { call, result ->
                        // 你的代码
                        if (call.method == "isHavePermission"){
                            result.success("有了-Android")
                        }else{
                            result.notImplemented()
                        }
                    }
        }
    }

此时,三部分的代码都完成了,运行看看效果

  • Android

  • iOS

文章目录