Flutter Plugin Package使用, WebView交互

Plugin Package使用, WebView交互

Flutter和原生ios/安卓交互

公开Plugin

在 Flutter 中与原生 iOS 和 Android 交互通常是通过创建插件(plugin)来实现的。这种方式允许你在 Flutter 应用中调用原生平台的代码和功能。以下是创建和使用 Flutter 插件进行原生交互的基本步骤:

1 创建 Flutter 插件

使用 Flutter 命令行工具可以轻松创建一个插件项目:

flutter create --template=plugin my_plugin


默认语言是swift和Kotlin

如果你想指定 iOS 的语言为 Objective-C 和 Android 的语言为 Java:

flutter create --template=plugin --platforms=ios,android --ios-language=objc --android-language=java my_plugin


2 编写原生代码

在创建的插件项目中,添加 Objective-C 和 Java 的原生代码。

3 iOS 示例(Objective-C):

my_plugin/ios/Classes/MyPlugin.m 文件中:

#import "MyPlugin.h"

 MyPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
  FlutterMethodChannel* channel = [FlutterMethodChannel
      methodChannelWithName:@"my_plugin"
            binaryMessenger:[registrar messenger]];
  MyPlugin* instance = [[MyPlugin alloc] init];
  [registrar addMethodCallDelegate:instance channel:channel];
}

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
  if ([@"getPlatformVersion" isEqualToString:call.method]) {
    result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
  } else {
    result(FlutterMethodNotImplemented);
  }
}



4 Android 示例(Java):

my_plugin/android/src/main/java/com/example/my_plugin/MyPlugin.java 文件中:

package com.example.my_plugin;

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;

/** MyPlugin */
public class MyPlugin implements FlutterPlugin, MethodCallHandler {
  private MethodChannel channel;

  
  public void onAttachedToEngine( FlutterPluginBinding flutterPluginBinding) {
    channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "my_plugin");
    channel.setMethodCallHandler(this);
  }

  
  public void onMethodCall( MethodCall call,  Result result) {
    if (call.method.equals("getPlatformVersion")) {
      result.success("Android " + android.os.Build.VERSION.RELEASE);
    } else {
      result.notImplemented();
    }
  }

  
  public void onDetachedFromEngine( FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
  }
}


5 vDart 代码交互

在 Dart 部分,你可以通过创建的插件与原生代码通信。

import 'package:flutter/services.dart';
import 'package:my_plugin/my_plugin.dart';

class MyPlugin {
  static const MethodChannel _channel = const MethodChannel('my_plugin');

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


6 在 Flutter 应用中使用插件

在你的 Flutter 应用中,添加对插件的依赖,并调用相关方法:

import 'package:my_plugin/my_plugin.dart';

// ...

Future<void> getPlatformVersion() async {
  String? version = await MyPlugin.platformVersion;
  print(version);
}


私有Plugin

上面的plugin一般得发布公开出去,让别人都可以用

如果你只是自己项目专用plugin 不想公开出去

建立本地私有plugin就行

直接 ios 安卓项目里创建类

ios

在ios项目里新建一个JDPlutin类



.h文件
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>

NS_ASSUME_NONNULL_BEGIN

 JDPlugin : NSObject<FlutterPlugin>



NS_ASSUME_NONNULL_END


.m文件

#import "JDPlugin.h"
#import "YBKeychainUtils.h"

//app名字
#define APP_DISPLAY_NAME        ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"])
//版本号1.0
#define APP_SHORT_VERSION       ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"])
// build号
#define APP_BUNDLE_VERSION      ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"])

 JDPlugin ()

 (nonatomic, strong) FlutterMethodChannel *channel;




 JDPlugin


+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
    FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:@"jd_learn_plugin" binaryMessenger:[registrar messenger]];
    JDPlugin *plugin = [[JDPlugin alloc] initWithChannel:channel];;
    [registrar addMethodCallDelegate:plugin channel:channel];
}

- (instancetype)initWithChannel:(FlutterMethodChannel *)channel {
    self = [super init];
    NSAssert(self, @"super init cannot be nil");
    self.channel = channel;
    return self;
}


//收到flutter调用
- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
    if ([@"getAppInfo" isEqualToString:call.method]) {
        [self handgetAppInfoMethodWithParam:call.arguments result:result];
    } else if ([call.method isEqualToString:@"jumpAppStore"]) {
        // appStore链接
        NSURL *url = [NSURL URLWithString:@"https://apps.apple.com/cn/app/idxxxxxx"];
        if ([[UIApplication sharedApplication] canOpenURL:url]) {
            [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
        }
    } else {
        if (result) {
            result(FlutterMethodNotImplemented);
        }
    }
}

//获取设备信息
- (void)handgetAppInfoMethodWithParam:(id)arguments result:(FlutterResult)result {
//    NSLog(@"flutter传过来的参数---> %@", arguments);
    /*
     deviceId : 设备唯一id 卸载后也不变
     appName : app名字
     packageName: app id
     appVersion 版本号
     buildNumber 当前版本build号
     device_model 设备机型
     os_version 系统版本
     */
    if (result) {
        result( @{@"deviceId" : [YBKeychainUtils deviceId],
                  @"appName" : APP_DISPLAY_NAME ?: @"",
                  @"packageName" : [[NSBundle mainBundle] bundleIdentifier] ?: @"",
                  @"appVersion" : APP_SHORT_VERSION ?: @"",
                  @"buildNumber" : APP_BUNDLE_VERSION ?: @"",
                  @"device_model" : [UIDevice currentDevice].model ?: @"",
                  @"os_version" : [UIDevice currentDevice].systemVersion ?: @"",
  
                });
    }
   
}

//直接调用flutter测试
- (void)nativeCallFlutterTest {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.channel invokeMethod:@"imagePath" arguments:@{@"key1" : @"ios 调用flutter value"}];
    });
}





注册私有plugin

 [JDPlugin registerWithRegistrar:[self registrarForPlugin:@"JDPlugin"]];

[GeneratedPluginRegistrant registerWithRegistry:self]; 就是公开的第三方plugin,公开统一注册

#import "AppDelegate.h"
#import "GeneratedPluginRegistrant.h"
#import "JDPlugin.h"

 AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GeneratedPluginRegistrant registerWithRegistry:self];
  [JDPlugin registerWithRegistrar:[self registrarForPlugin:@"JDPlugin"]];
  // Override point for customization after application launch.
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}




安卓

1 app-src-main-java-包名 下新建JDPlugin类

package com.example.jd_flutter.jdPlugin;


import androidx.annotation.NonNull;

import java.util.HashMap;
import java.util.Map;


import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;


import com.example.jd_flutter.MainActivity;

import io.flutter.Log;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.Result;


public class JDPlugin implements FlutterPlugin, MethodChannel.MethodCallHandler {
    private final MainActivity mActivity;

    public JDPlugin(MainActivity activity) {
        this.mActivity = activity;
    }

    private MethodChannel channel;

    private JDPlugin currentPlugin;

    
    public void onAttachedToEngine( FlutterPluginBinding binding) {
        Log.e("安卓 onAttachedToEngine", "111");

        BinaryMessenger messenger = binding.getBinaryMessenger();
        channel = new MethodChannel(messenger, "jd_learn_plugin");
        channel.setMethodCallHandler(this);
        currentPlugin = this;
        this.mActivity.currentPlugin = currentPlugin;
    }

    
    public void onDetachedFromEngine( FlutterPluginBinding binding) {
        channel.setMethodCallHandler(null);
        channel = null;
        currentPlugin = null;
        this.mActivity.currentPlugin = null;
    }

    //flutter调用安卓
    
    public void onMethodCall(final MethodCall call, final Result result) {
        Log.e("收到原生调用11 onMethodCall", call.method);
        if ("getAppInfo".equals(call.method)) {
            //获取app信息
            try {
                getAppInfo(call.arguments, result);
            } catch (PackageManager.NameNotFoundException e) {
                throw new RuntimeException(e);
            }
        } else {
            if (result != null) {
                result.notImplemented();
            }
        }
    }


    private void getAppInfo(Object args, Result result) throws PackageManager.NameNotFoundException {
        // 获取设备信息
        if (result != null) {
            Map<String,String> map = new HashMap();
            PackageManager packageManager = this.mActivity.getApplicationContext().getPackageManager();
            // 获取当前包的信息
            PackageInfo packageInfo = packageManager.getPackageInfo(this.mActivity.getApplicationContext().getPackageName(), 0);
            // 获取版本名称和版本号
            String versionName = packageInfo.versionName;
            map.put("version", versionName);
            map.put("buildNumber", getLongVersionCode(packageInfo));
            Log.d("安卓 回调给 flutter", map.toString());
            result.success(map);
        }
    }

    String getLongVersionCode(PackageInfo info ) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
             return  Long.toString(info.getLongVersionCode());
        } else {
             return String.valueOf(info.versionCode);
        }
    }

    //安卓调用flutter
    private void invokeMethod(String method, Object args) {
        currentPlugin.channel.invokeMethod(method, args);
    }

}




注册安卓私有plugin

package com.example.jd_flutter;

import androidx.annotation.NonNull;

import com.example.jd_flutter.jdPlugin.JDPlugin;

import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;

public class MainActivity extends FlutterActivity {
    public JDPlugin currentPlugin;
    
    public void configureFlutterEngine( FlutterEngine flutterEngine) {
        super.configureFlutterEngine(flutterEngine);

        flutterEngine.getPlugins().add(new com.example.jd_flutter.jdPlugin.JDPlugin(this));
    }
}


Flutter使用私有插件 获取版本信息

import 'dart:io';

import 'package:flutter/services.dart';
import 'package:jd_flutter/base/utils/jd_log.dart';

class JDPluginInstance {
  // 推送点击
  static const String kPushClick = 'pushClick';

  static const MethodChannel tdChannel = MethodChannel('jd_learn_plugin');

  factory JDPluginInstance() => _instance;
  static final JDPluginInstance _instance = JDPluginInstance._internal();

  JDPluginInstance._internal() {
    //app调用flutter方法处理
    tdChannel.setMethodCallHandler((call) {
      if (call.method == kPushClick) {
        jdLog("native调用了flutter ${call.arguments}");
        if (call.arguments is Map) {
          dealPushClick(param: Map<String, dynamic>.from(call.arguments));
        }
      }
      return Future(() {});
    });
  }

  dealPushClick({Map<String, dynamic>? param}) {
    //处理push点击
  }

  Future<String> sendMsgToNative(String method,
      {Map<String, dynamic>? param}) async {
    jdLog("flutter 开始 native调用了flutter ");
    String result = await tdChannel.invokeMethod(method, param);
    jdLog("flutter 收到native的返回值 $result");
    return result;
  }

  // 获取设备信息
  Future<Map> getAppInfo() async {
    Map info = await tdChannel.invokeMethod("getAppInfo");
    return info;
  }

  jumpToIosAppstore() {
    if (!Platform.isIOS) {
      return;
    }
    jdLog("jumpToIosAppstore");
    tdChannel.invokeMethod("jumpAppStore");
  }
}


Package

在 Flutter 中,“package” 指的是一个包含 Dart 代码的模块,它可以是纯 Dart 代码的库,也可以是提供特定功能(如 UI 组件、工具类、网络请求等)的插件。Flutter 的包和插件是它的生态系统的重要部分,它们允许开发者重用代码并实现快速开发。

创建 Flutter Package

要创建一个新的 Flutter package,你可以使用以下命令:

flutter create --template=package my_package


这将创建一个包含基本目录结构和配置文件的新 Dart package。

包的结构

一个典型的 Flutter package 包括以下部分:

  • lib/ 目录:包含 package 的主要 Dart 代码。
  • test/ 目录:包含 package 的单元测试。
  • pubspec.yaml 文件:定义了 package 的元数据,包括名称、版本、描述、依赖等。
添加依赖

在你的 Flutter 项目中,你可以通过修改 pubspec.yaml 文件来添加一个 package 作为依赖。这可以是来自 pub.dev的公共包,也可以是本地路径或 Git 仓库。

dependencies:
  flutter:
    sdk: flutter
  http: ^0.13.3 # 示例:添加 http 包


然后运行 flutter pub get 来获取包。

使用 Package

在获取包之后,你可以在你的项目中导入并使用它:

import 'package:http/http.dart' as http;

void fetchData() async {
  var response = await http.get(Uri.parse('https://example.com'));
  print(response.body);
}


在这个例子中,我们使用 http 包发送 HTTP 请求。

发布 Package

如果你创建了自己的 package,并想将其分享给社区,你可以将它发布到 pub.dev。在发布之前,请确保遵循以下准则:

  • 编写有效的文档和示例。
  • 确保代码质量,包括格式化和单元测试。
  • 遵循 Dart 的包版本管理指南。

使用 flutter pub publish 命令可以将你的 package 发布到 pub.dev。

通过创建和使用 Flutter packages,你可以有效地构建和共享可重用的代码,这是 Flutter 开发的一个重要方面。如果只是本地项目使用,则不用发布到pub.dev.

Flutter和Webview交互

在 Flutter 中,flutter_inappwebview 插件是一个非常强大的库,用于在 Flutter 应用中嵌入 Web 内容,并提供了 Flutter 与 WebView 之间的交互功能。这种交互通常涉及到两个主要方面:Flutter 向 WebView 发送数据或调用 JavaScript 函数,以及 WebView 向 Flutter 发送数据或触发事件。

  1. Flutter 向 WebView 发送数据或调用 JavaScript

使用 InAppWebViewController,你可以执行 WebView 中的 JavaScript 代码。

在这个例子中,evaluateJavascript 方法被用来在 WebView 中执行 JavaScript 函数 javascriptFunction()

  1. WebView 向 Flutter 发送数据或触发事件

你可以通过 JavaScript 向 Flutter 发送消息。首先,需要在 WebView 中定义好发送消息的 JavaScript 代码,然后在 Flutter 中使用 InAppWebViewonConsoleMessageonLoadStop 或其他相关回调来接收这些消息。

在 HTML/JavaScript 中:

// js调用flutter
function sendMessageToFlutter() {   window.flutter_inappwebview.callHandler('handlerFoo', 'Hello from JS!').then(function(result) {
        // 打印Flutter回调的内容
        console.log(result);
     });;
  }
}

//js让flutter调用方法
function myFunction(message) {
    alert("Received message: " + message);
    return "Data from JavaScript";
}



Flutter 注册js调用方法

InAppWebView(
  initialUrl: "https://yourwebsite.com",
  onLoadStop: (controller, url) async {
    controller.addJavaScriptHandler(handlerName: 'handlerFoo', callback: (args) {
      // 这里是从 JavaScript 接收到的消息
      print('Received message from JavaScript: ${args[0]}');
       return {'success': 1};
    });
  },
);


在这个例子中,当 sendMessageToFlutter() 被 JavaScript 调用时,Flutter 中的 addJavaScriptHandler 回调会被触发,并接收到从 JavaScript 发送的消息。

Flutter调用js方法

 Future<void> callJavaScriptFunction() async {
  try {
    // 调用 JavaScript 函数并获取返回值
    var result = await _webViewController.evaluateJavascript(source: "myFunction('flutter string')");
    print("JavaScript function returned: $result");
  } catch (e) {
    print("Error calling JavaScript function: $e");
  }
}

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
img
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓(文末还有ChatGPT机器人小福利哦,大家千万不要错过)

PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题
图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值