[Flutter] Hướng Dẫn Tạo Plugin Và Gọi Thư Viện Native (Phần Cuối)

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

Xem thêm Phần 1-2 Xem thêm Phần 3

Phần 4: Hướng dẫn thêm thư viện native

Trong phần này, mình sẽ demo việc gửi 1 DateTime từ flutter xuống native code để kiểm tra xem có phải ngày hiện tại hay không? Mình sẽ sử dụng thư viện Tempo của tác giả cesarferreira cho Android và SwiftDate của tác giả Daniele Margutti cho iOS.

Vì flutter và native không giao tiếp với nhau bằng biến loại DateTime được, nên mình sẽ cần chuyển DateTime sang dạng string UTC để xử lý nhé.

Thêm code flutter để hiển thị kết quả

Trong file lib/src/sample_call_native.dart các bạn thêm 1 hàm như sau:

static Future isToday(DateTime dateTime) async { final date = dateTime.toUtc().toIso8601String(); final bool? isSuccess = await _channel.invokeMethod( 'isToday', { 'dateTime': date, }, ); return isSuccess; }

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 ?? ''); }, ), /// Phần 4. Hướng dẫn gọi native code từ plugin FutureBuilder( future: SampleCallNativeFlutter.isToday(DateTime.now()), builder: (_, snapshoot) { return Text('isToDay: ${DateTime.now()} is ${snapshoot.data}'); }, ), FutureBuilder( future: SampleCallNativeFlutter.isToday(DateTime(2021,01,01)), builder: (_, snapshoot) { return Text('isToDay: ${DateTime(2021,01,01)} is ${snapshoot.data}'); }, ), ], ), ), ), ); } }

Thêm thư viện cho iOS

Thường khi thêm 1 thư viện vào code iOS, bạn cần sử dụng Cocoapods thêm nó vào Podfile. Nhưng với plugin thì bạn sẽ thêm dependency nó vào ios/sample_plugin_flutter.podspec.

File này cũng giúp bạn khai báo s.static_framework = true(1 số thư viện native cần phải khai báo biến này) hay s.ios.deployment_target = ‘9.0’ (để giới hạn version build iOS).

(Nếu bạn chưa biết Cocoapods là gì, bạn có thể tham khảo tại đây)

# # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. # Run `pod lib lint sample_plugin_flutter.podspec` to validate before publishing. # Pod::Spec.new do |s| s.name = 'sample_plugin_flutter' s.version = '0.0.1' s.summary = 'A new flutter plugin project.' s.description = < '../LICENSE' } s.author = { 'Your Company' => '[email protected]' } s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.dependency 'Flutter' s.dependency 'SwiftDate' # Khai báo thư viện iOS tại đây s.platform = :ios, '8.0' # Flutter.framework does not contain a i386 slice. s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } s.swift_version = '5.0' end

Sau đó bạn cần chạy pod install cho thư mục example/ios và vào Xcode chọn menu Product/Clean Build Folder. Trong file SwiftSamplePluginFlutterPlugin bạn đổi lại code như sau:

import Flutter import UIKit import SwiftDate 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) case "isToday": isToday(call, result) default: result(nil) } } private func isToday(_ call: FlutterMethodCall,_ result: @escaping FlutterResult) { let arguments = call.arguments as! Dictionary let dateTime = arguments["dateTime"] as! String; // Convert to local let localDate = dateTime.toDate(nil, region: Region.current) // Check isToday let checkToday = localDate?.isToday result(checkToday) } }

Thế là xong bên iOS, giờ qua phần của Android.

Thêm thư viện cho Android

Trong Gradle Scripts/build.gradle(Module: android.sample_plugin_flutter) bạn thêm dòng bên dưới ở cuối file và nhấn Sync now

dependencies { implementation 'com.github.cesarferreira:tempo:+' }

Sample 5

Trong file android/src/main/kotlin/com/example/sample_plugin_flutter/SamplePluginFlutterPlugin.kt bạn đổi lại code như sau:

package com.example.sample_plugin_flutter import androidx.annotation.NonNull import com.cesarferreira.tempo.Tempo import com.cesarferreira.tempo.isToday 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 import java.text.SimpleDateFormat import java.util.* /** 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}") "isToday" -> isToday(call, result) else -> { result.notImplemented() } } } private fun isToday(@NonNull call: MethodCall, @NonNull result: Result) { var arguments = call.arguments as Map var dateTime = arguments["dateTime"] as String var localDate = dateTime.toDate() var checkToday = localDate.isToday // library Tempo check isToday result.success(checkToday) } private fun String.toDate(dateFormat: String = "yyyy-MM-dd'T'HH:mm:ss", timeZone: TimeZone = TimeZone.getTimeZone("UTC")): Date { val parser = SimpleDateFormat(dateFormat, Locale.getDefault()) parser.timeZone = timeZone return parser.parse(this) } override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { channel.setMethodCallHandler(null) } }

Xong rồi, giờ chạy flutter run để xem thành quả cuối cùng thôi nào.

Sample 6

Kết thúc

Hi vọng qua bài viết của mình giúp ích cho các bạn phần nào việc làm qua viết plugin cho Flutter. Mình để link Github ở đây để các bạn tham khảo nha.

Nguồn tham khảo:

  • Developing packages & plugins
  • Bảng mapping các loại biến giữa các nền tảng
  • Thư viện Tempo
  • Thư viện SwiftDate
  • Cocoapods

Bài viết đầy đủ tại Viblo Cảm ơn các bạn đã xem bài viết.

Tác giả

Phạm Tiến Dũng [email protected]

Từ khóa » Thư Viện Flutter