[Flutter] Hướng dẫn tạo plugin và gọi thư viện native (Phần 3)

Xem lại Phần 1-2

Phần 3. Hướng dẫn gọi native code từ plugin

1. Làm việc với IDE native

Khi làm việc với native code, bạn nên dùng Android Studio khi code Android và Xcode khi code iOS nhé. 2 IDE này sẽ hỗ trợ bạn tốt hơn trong việc báo lỗi và cả debug code.

  • Trong Android Studio bạn mở thư mục example/android/, giao diện cây thư mục trong IDE sẽ như thế này. Sample 2

  • Trong Xcode bạn mở thư mục example/ios/Runner.xcworkspace, giao diện cây thư mục trong IDE sẽ như thế này. Sample 3

2. Code native cho plugin

Để gọi native code, bạn sẽ cần sử dụng channel, thường channel nên được đặt cùng tên với tên plugin của bạn. Thông qua channel chúng ta sẽ gọi hàm native và nhận kết quả từ đó.

Các bạn có thể tham khảo mapping các loại biến giữa các nền tảng tại đây.

Trong thư mục lib/src các bạn tạo 1 file dart mới và đặt tên là sample_call_native.dart. File này sẽ tạo MethodChannel(‘sample_plugin_flutter’) để liên kết đến native code và hàm platformVersion() để kiểm tra version của thiết bị người dùng.

import 'dart:async';

import 'package:flutter/services.dart';

class SampleCallNativeFlutter {
  static const MethodChannel _channel =
      const MethodChannel('sample_plugin_flutter');

  static Future get platformVersion async {
    final String? version = await _channel.invokeMethod('getPlatformVersion');
    return version;
  }
}

Trong file lib/src/src.dart các bạn thêm dòng export.

export 'sample_call_native.dart';

Trong file android/src/main/kotlin/com/example/sample_plugin_flutter/SamplePluginFlutterPlugin.kt đã code demo sẵn channel và cách trả về platformVersion như minh họa phía dưới. Tại hàm onMethodCall, cần kiểm tra tên call.method được gọi là gì và trả về cho flutter kết quả thông qua result.success().

Lưu ý: nếu bạn gọi 1 function không cần trả kết quả, bạn vẫn phải gọi result.success(null) để báo về cho flutter biết hàm đã thực hiện xong.

package com.example.sample_plugin_flutter

import androidx.annotation.NonNull

import io.flutter.embedding.engine.plugins.FlutterPlugin
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

/** SamplePluginFlutterPlugin */
class SamplePluginFlutterPlugin: FlutterPlugin, MethodCallHandler {
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  private lateinit var channel : MethodChannel

  override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
    channel = MethodChannel(flutterPluginBinding.binaryMessenger, "sample_plugin_flutter")
    channel.setMethodCallHandler(this)
  }

  override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
    when (call.method) {
      "getPlatformVersion" -> result.success("Android ${android.os.Build.VERSION.RELEASE}")
      else -> {
        result.notImplemented()
      }
    }
  }

  override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
    channel.setMethodCallHandler(null)
  }
}

Tương tự trong file ios/Classes/SwiftSamplePluginFlutterPlugin.swift đã code demo sẵn channel và cách trả về platformVersion như minh họa phía dưới. Tại hàm handle, cần kiểm tra tên call.method được gọi là gì và trả về cho flutter kết quả thông qua result(). Nếu bạn gọi 1 function không cần trả kết quả, bạn vẫn cần gọi result(nil) để báo về cho flutter biết hàm đã thực hiện xong.

import Flutter
import UIKit

public class SwiftSamplePluginFlutterPlugin: NSObject, FlutterPlugin {
  public static func register(with registrar: FlutterPluginRegistrar) {
    let channel = FlutterMethodChannel(name: "sample_plugin_flutter", binaryMessenger: registrar.messenger())
    let instance = SwiftSamplePluginFlutterPlugin()
    registrar.addMethodCallDelegate(instance, channel: channel)
  }

  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
    switch call.method {
    case "getPlatformVersion":
        result("iOS " + UIDevice.current.systemVersion)
    default:
        result(nil)
    }
  }
}

Trong file example/lib/main.dart bạn đổi lại code như sau:

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              /// Phần 2. Hướng dẫn tạo Widget với plugin
              SampleButton(
                text: "Sample Button",
                onPressed: () {
                  print("Sample Button Click");
                },
              ),

              /// Phần 3. Hướng dẫn gọi native code từ plugin
              FutureBuilder(
                future: SampleCallNativeFlutter.platformVersion,
                builder: (_, snapshoot) {
                  return Text(snapshoot.data ?? '');
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Chạy flutter run để xem kết quả thôi nào.

Sample 4

Còn tiếp

Bài viết đầy đủ tại Viblo

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.