前言
在开发一个上线的app过程中,单纯的依赖某一种框架在当前基本不存在,不可避免的需要多种技术参与。
本文以集成百度地图为例,详细讲述如何在flutter中集成android原生模块,flutter怎么调用java,以及java如何通知flutter。
为什么以百度地图为例呢,百度地图含jar和so,比较全面,又是一个视图型的框架,比较容易看到结果。
创建一个plugin
命令行中运行
flutter create --template=plugin futter_baidu_map
在android-studio打开项目
按照百度地图官方文档集成android版本
文档地址:
http://lbsyun.baidu.com/index...
这里选择想要的模块:
下载之后是这样一个结构:
全部放到刚才创建项目的android项目的libs目录中,这个目录如果不存在需要创建一下,最后的目录结构如下:
修改一下build.gradle,增加依赖
打开FlutterBaiduMapPlugin编辑,初次打开会出现这个提示:
点击一下右上角的 "Setup SDK",
这里按需选择配置,这里我选择了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
然后就可以愉快的使用了。
总结一下:
1、flutter调用java:
创建plugin,并在java的Plugin实现类中实现onMethodCall方法
2、java调用flutter:
在java中使用MethodChannel调用方法,并在dart中使用StreamController结合StreamController.stream实现监听。
3、其他项目使用plugin
编辑pubspec.yaml,增加本地依赖,或者发布到pub.dartlang.org
代码:
https://github.com/jzoom/flut...
如有疑问,请加qq群854192563讨论