Flutter 入門-本地訪問-MethodChannel

黃馬發表於2018-06-29

Dart4Flutter - 01 – 變數、型別和函式

Dart4Flutter – 02 –控制流 和異常

Dart4Flutter – 03 – 類和泛型

Dart4Flutter – 04 – 非同步和庫

Dart4Flutter - 拾遺01 - flutter-dart環境搭建

Dart4Flutter - 不可變性

Flutter入門 - 狀態管理

Flutter 入門例項1

Flutter 入門 - Container 屬性詳解

Flutter 入門-本地訪問-MethodChannel

Flutter 例項 - 載入更多的ListView

Flutter 例項 - 從本地到Flutter通訊 - Event Channels

Flutter 入門-本地訪問-MethodChannel

Flutter 作為一種跨平臺的解決方案,有訪問本地資源的能力。主要是通過Channel完成,你可以稱之為隧道。主要是MethodChannel和MessageChannel兩種,第一種是呼叫方法,第二種是傳遞資訊。首先通訊的雙方是Flutter和本地作業系統或者應用,而且方法的呼叫和訊息的方法可以從任何一方發起,類似RPC(遠端過程呼叫)。

重點內容:

  • 主要是Flutter是一個比較獨立的環境,要想訪問本地的資源,Flutter提供了Channel機制,類似Cilent-Server模式或者RPC
  • 通過Channel的名稱打通Channel,隧道。
  • Flutter和本地是對稱的,請求可以從任何一發發起,本教程主要是從Flutter給本地傳送請求。

Flutter部分

如果你對Flutter的介面編寫部分不熟悉,可以參考官方的文件;

下面是UI部分的程式碼

import 'package:flutter/material.dart';


void main() {
  runApp(new MaterialApp(
    home: new Scaffold(
      body: new PlatformTestBody(),
    ),
  ));
}

class PlatformTestBody extends StatefulWidget {
  @override
  PlatformTestBodyState createState() {
    return new PlatformTestBodyState();
  }
}

class PlatformTestBodyState extends State<PlatformTestBody> {

  String nativeMessage =''; 
  @override
  Widget build(BuildContext context) {
    return new Container(
      color: Colors.pinkAccent,
      child: new Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          new Padding(
            padding: const EdgeInsets.only(left: 18.0, top: 200.0),
            child: new Text(
              'Tap the button to change your life!',
              style: new TextStyle(
                  color: Colors.white,
                  fontWeight: FontWeight.w500,
                  fontSize: 23.0),
            ),
          ),
          new Padding(
            padding: const EdgeInsets.only(left: 8.0, right: 8.0, top: 102.0),
            child: new RaisedButton(
              child: new Text('Click Me'),
              onPressed: () => print(''),
            ),
          ),
          new Padding(
            padding: const EdgeInsets.only(left: 8.0, right: 8.0, top: 102.0),
            child: new Text(
              nativeMessage,
              style: new TextStyle(
                  color: Colors.white,
                  fontWeight: FontWeight.w500,
                  fontSize: 23.0),
            ),
          )
        ],
      ),
    );
  }
}
複製程式碼

現在我們介紹關於本地資源訪問的問題,首先我們要引入service包和async包。

// Add these lines to the top of the file
import 'package:flutter/services.dart';
import 'dart:async';
複製程式碼

有了service包,我們就可以配置Flutter,傳送請求到本地。宣告一個static const變數platformMethodChannel ,賦值MethodChannel型別的物件。

class PlatformTestBodyState extends State<PlatformTestBody> {
  //Add this line 
  static const platformMethodChannel = const MethodChannel('com.test/test');

  String nativeMessage ='';  
  @override
  Widget build(BuildContext context) {
      ...
複製程式碼

注意,我們給MethodChannel一個名字com.test/test,這個名字和本地那邊的要一樣。

我們建立了MethodChannel,我們準備一個用來傳送請求的函式。我們建立一個叫doNativeSuff的非同步函式

Future<Null> doNativeSuff() async {
 
  }
複製程式碼

代替RaisedButton中的onPressed函式 print('')doNativeSuff()

child: new RaisedButton(
    child: new Text('Click Me'),
    onPressed: () => print(''),
),
複製程式碼
child: new RaisedButton(
    child: new Text('Click Me'),
    onPressed: () => doNativeSuff(),
),
複製程式碼

下面解釋整個doNativeSuff 方法

Future<Null> doNativeSuff() async {
    String _message; // 1
    try {
      final String result =
          await platformMethodChannel.invokeMethod('changeLife');// 2
      _message = result;
      print(result);
    } on PlatformException catch (e) {
      _message = "Sadly I can not change your life: ${e.message}.";
    }
    setState(() {
        nativeMessage = _message; // 3
    });
  }
複製程式碼
  1. 宣告一個String變數_message,用於存需要顯示在介面上的資訊,可能來自本地,也可能來自Flutter
  2. 傳送請求,await platformMethodChannel.invokeMethod('changeLife') 是呼叫本地的changeLife 方法,並且這個方法是非同步的,await表示阻塞執行。
  3. nativeMessage = _message; 表示通知Flutter狀態改變,重新整理介面。

本地部分

本教程只關注Android方面的程式碼。在Android studio 中開啟MainActivity.java,在檔案的最頂上新增一下程式碼,是Flutter外掛的相關依賴

import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
複製程式碼

宣告CHANNEL 變數,和Flutter中MethodChannel的名字一樣com.test/test,建議直接從Flutter那邊複製貼上。

public class MainActivity extends FlutterActivity {
  private static final String CHANNEL = "com.test/test"; 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    ...
複製程式碼

使用上面的CHANNELFlutterView 建立一個MethodChannel

public class MainActivity extends FlutterActivity {
  private static final String CHANNEL = "com.test/test";
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    GeneratedPluginRegistrant.registerWith(this);
    new MethodChannel(getFlutterView(), CHANNEL)// 重點
複製程式碼

在MethodChannel的中呼叫.setMethodCallHandler() 方法,需要一個MethodCallHandler 物件,是一個匿名內部類,有一個方法onMethodCall,在Flutter傳送請求事,onMethodCall方法會執行。

public class MainActivity extends FlutterActivity {
  private static final String CHANNEL = "com.test/test";
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    GeneratedPluginRegistrant.registerWith(this);
    new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
      new MethodCallHandler() {
        @Override
        public void onMethodCall(MethodCall methodCall, Result result) {
        }
      }
    );
  }

}
複製程式碼

onMethodCall方法中有兩個引數 MethodCall 和 result,MethodCall 中有關當前請求的資訊,例如呼叫方法的名字changeLife;Result用於傳送資訊給Flutter。

在onMethodCall中判斷當前請求是否為changeLife,如果是通過resultsuccess 返回資訊:Life Changed .

public void onMethodCall(MethodCall methodCall, Result result) {
  if (methodCall.method.equals("changeLife")){
    String message ="Life Changed";
    result.success(message);
  }
  ...
複製程式碼

這樣Flutter就可以訪問,本地的方法了。

通常應用於訪問本地資源,例如訪問相機,本地儲存,圖片的選擇

本教程主要了解的是MethodChannel,還有MessageChannel沒有解析,下次再說。

參考

相關文章