flutter怎樣集成原生模塊android版,以及現階段會遇到的坑和解決方法

前言

在開發一個上線的app過程當中,單純的依賴某一種框架在當前基本不存在,不可避免的須要多種技術參與。php

本文以集成百度地圖爲例,詳細講述如何在flutter中集成android原生模塊,flutter怎麼調用java,以及java如何通知flutter。java

爲何以百度地圖爲例呢,百度地圖含jar和so,比較全面,又是一個視圖型的框架,比較容易看到結果。android

建立一個plugin

命令行中運行git

flutter create --template=plugin futter_baidu_map

在android-studio打開項目github

按照百度地圖官方文檔集成android版本

文檔地址:api

http://lbsyun.baidu.com/index...android-studio

這裏選擇想要的模塊:app

下載以後是這樣一個結構:框架

clipboard.png

所有放到剛纔建立項目的android項目的libs目錄中,這個目錄若是不存在須要建立一下,最後的目錄結構以下:async

clipboard.png

修改一下build.gradle,增長依賴

clipboard.png

打開FlutterBaiduMapPlugin編輯,初次打開會出現這個提示:

clipboard.png

點擊一下右上角的 "Setup SDK",

clipboard.png

這裏按需選擇配置,這裏我選擇了Anroid API 27 Platform.

下面編輯咱們想要的功能,這個時候坑來了:

這裏雖然導入了百度地圖的庫,依賴也加了,可是android studio竟然識別不出來!!!!這個問題困擾了我n久,甚至還搞了一套flutter的fake代碼放在其餘項目中。

轉折來了......今天突然發現這裏有個菜單:

點擊一下,android-studio會新開一個項目:

神奇的發現,那些紅色的不能識別的代碼都消失了!!!

繼續往下搞:

集成定位功能

按照這裏的指示增長一些配置,申請一個key,這裏就不細說了
http://lbsyun.baidu.com/index...

初始化地圖SDK(flutter調用java)_

修改java文件:com.example.flutterbaidumap.FlutterBaiduMapPlugin

public class FlutterBaiduMapPlugin implements MethodCallHandler {

  private Activity activity;
  private LocationManager mSysLocManager;


  public FlutterBaiduMapPlugin(Activity activity) {
    this.activity = activity;
  }

  /**
   * Plugin registration.
   */
  public static void registerWith(Registrar registrar) {
    final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_baidu_map");
    channel.setMethodCallHandler(new FlutterBaiduMapPlugin( registrar.activity() ));
  }

  @Override
  public void onMethodCall(MethodCall call, Result result) {
    if (call.method.equals("init")) {
      SDKInitializer.initialize(activity.getApplicationContext());
      try {
        if (mSysLocManager == null) {
          /** 獲取系統的定位服務管理類*/
          mSysLocManager = (LocationManager) JNIInitializer.getCachedContext()
                  .getSystemService(Context.LOCATION_SERVICE);
        }
        //成功返回true
        result.success(true);

      } catch (Exception e) {
        // 失敗返回false
        result.success(false );
      }

    } else {
      result.notImplemented();
    }
  }
}

在dart中調用:修改flutter_baidu_map.dart

import 'dart:async';

import 'package:flutter/services.dart';

class FlutterBaiduMap {
  static const MethodChannel _channel =
      const MethodChannel('flutter_baidu_map');

  static Future<bool> init() async {
    return await _channel.invokeMethod('init');
  }
}

在example的main.dart中這麼調用

@override
  initState() {

    initBaidu();

    super.initState();
  }

  void initBaidu() async{
    bool result = await FlutterBaiduMap.init();
    if(result){
      print("百度地圖加載成功...");
    }else{
      print("百度地圖加載失敗...");
    }
  }

運行輸出:

監聽地理位置(java通知flutter)

java文件增長判斷,並增長一個MethodChannel的引用,向flutter發送消息全靠他了。

package com.example.flutterbaidumap;

import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;

import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.PluginRegistry.Registrar;

import com.baidu.mapapi.JNIInitializer;

import com.baidu.mapapi.SDKInitializer;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;


/**
 * FlutterBaiduMapPlugin
 */
public class FlutterBaiduMapPlugin implements MethodCallHandler {

    private Activity activity;
    private LocationManager mSysLocManager;
    private MethodChannel channel;

    public FlutterBaiduMapPlugin(Activity activity,MethodChannel channel) {
        this.activity = activity;
        this.channel = channel;
    }

    /**
     * Plugin registration.
     */
    public static void registerWith(Registrar registrar) {
        final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_baidu_map");

        channel.setMethodCallHandler(new FlutterBaiduMapPlugin(registrar.activity(),channel));
    }

    @Override
    public void onMethodCall(final MethodCall call, final Result result) {
        if (call.method.equals("init")) {
            SDKInitializer.initialize(activity.getApplicationContext());
            try {
                if (mSysLocManager == null) {
                    /** 獲取系統的定位服務管理類*/
                    mSysLocManager = (LocationManager) JNIInitializer.getCachedContext()
                            .getSystemService(Context.LOCATION_SERVICE);
                }
                //成功返回true
                result.success(true);

            } catch (Exception e) {
                // 失敗返回false
                result.success(false);
            }

        } else if (call.method.equals("startLocation")) {

            mSysLocManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, listener);
            result.success(true);


        } else {
            result.notImplemented();
        }
    }


    private LocationListener listener = new LocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            Map<String,Object> data = new HashMap<String,Object>();
            data.put("latitude",location.getLatitude());
            data.put("longitude",location.getLongitude());
            data.put("result", "onLocationChanged");
            channel.invokeMethod("onLocation" ,data );
        }

        @Override
        public void onStatusChanged(String s, int i, Bundle bundle) {
            Map<String,Object> data = new HashMap<String,Object>();
            data.put("result", "status");
            channel.invokeMethod("onLocation" ,data );

        }

        @Override
        public void onProviderEnabled(String s) {
            Map<String,Object> data = new HashMap<String,Object>();
            data.put("result", "onProviderEnabled");
            channel.invokeMethod("onLocation" ,data );

        }

        @Override
        public void onProviderDisabled(String s) {
            Map<String,Object> data = new HashMap<String,Object>();
            data.put("result", "onProviderDisabled");
            channel.invokeMethod("onLocation" ,data );
        }
    };

}

增長調用,修改flutter_baidu_map.dart,這裏須要使用StreamController的add方法增長事件,並使用StreamController的stream增長一個監聽:

static Future<bool> init() async {
    _channel.setMethodCallHandler(handler); //注意這裏須要設置一下監聽函數
    return await _channel.invokeMethod('init');
  }
  static StreamController<Map> _locationUpdateStreamController = new StreamController.broadcast();
  static Stream<Map> get locationUpdate=>_locationUpdateStreamController.stream;

  static Future<dynamic> handler(MethodCall call) {
    String method = call.method;

    switch (method) {
      case "onLocation":
        {
          _locationUpdateStreamController.add( call.arguments );
        }
        break;
    }
    return new Future.value("");
  }

修改main.dart

void initBaidu() async{
    bool result = await FlutterBaiduMap.init();
    if(result){
      print("百度地圖加載成功...");

     await FlutterBaiduMap.startLocation();
      print("正在監聽...");

        //這裏監聽位置改變
      FlutterBaiduMap.locationUpdate.listen(  (Map data){
        print("獲取到百度地圖定位:$data");
      });

    }else{
      print("百度地圖加載失敗...");
    }
  }

輸出:

其餘項目使用這個模塊:

一種方法是發佈到https://pub.dartlang.org 上去,參考官網指引:https://flutter.io/developing...

另外一種是這邊要講的:本地依賴

把使用flutter_baidu_map模塊的項目放在同一層目錄中(實際上這個也沒有必要),編輯調用方的pubspec.yaml,增長依賴:

沒錯,就這麼簡單,而後在這個項目中運行一下:

flutter package get

而後就能夠愉快的使用了。

總結一下:

一、flutter調用java:

建立plugin,並在java的Plugin實現類中實現onMethodCall方法

二、java調用flutter:

在java中使用MethodChannel調用方法,並在dart中使用StreamController結合StreamController.stream實現監聽。

三、其餘項目使用plugin
編輯pubspec.yaml,增長本地依賴,或者發佈到pub.dartlang.org

代碼:

https://github.com/jzoom/flut...

若有疑問,請加qq羣854192563討論

相關文章
相關標籤/搜索