Flutter原生功能调用插件flutter_native_helper的使用

发布于 1周前 作者 itying888 来自 Flutter

Flutter原生功能调用插件flutter_native_helper的使用

flutter_native_helper

向Flutter端提供原生Android功能,包括:

  • 应用内升级
  • 获取系统铃声/通知/警报列表
  • 播放、暂停铃声/通知/警报

安装

pubspec.yaml 内.

最新版本:查看

dependencies:
  flutter_native_helper: ^$latestVersion

导入

在你要使用的类中.

import 'package:flutter_native_helper/flutter_native_helper.dart';

配置

1. 在 android/build.gradle,找到:

ext.kotlin_version = '1.3.10'

classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.10"

1.3.10 修改为 1.5.20


2. 在 android/app/src/main/res 下,新建 xml 文件夹,

随后在 xml 内新建 file_provider_path.xml 文件,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <root-path name="root" path="."/>
    <files-path
    name="files"
    path="."/>
    <cache-path
    name="cache"
    path="."/>
    <external-path
    name="external"
    path="."/>
    <external-cache-path
    name="external_cache"
    path="."/>
    <external-files-path
    name="external_file"
    path="."/>
</paths>

最后,打开 android/app/src/main/AndroidManifest.xml 文件, 在 application 标签下添加:

<provider
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true"
    android:name="androidx.core.content.FileProvider">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_provider_path" />
</provider>

使用

一、应用内升级

在之前,想要完成当前应用内升级,在Flutter端是不太便捷的事情,但现在,它将改变 - 你只需要一行代码,即可完成应用内升级(无需关注权限问题)。

1. 下载并安装

/// 注意:该方法仅会将apk下载到沙盒目录下
/// 这个示例最终生成的文件路径就是 '/data/user/0/$applicationPackageName/files/updateApk/new.apk'
/// 如果我想指定两层目录怎么办呢,很简单,只需要将 [fileDirectory] 设置为 'updateApk/second'
/// 那么他就会生成 '/data/user/0/$applicationPackageName/files/updateApk/second/new.apk'
///
/// 如果,连续多次调用此方法,并且三个参数为完全相同的,那么 Native 端将等待第一个下载完成后才允许继续下载。
FlutterNativeHelper.instance.downloadAndInstallApk(
    fileUrl: "https://xxxx.apk",
    fileDirectory: "updateApk",
    fileName: "new.apk");
参数名称 参数意义 是否必传
fileUrl 要下载apk的url地址
fileDirectory 文件夹路径(首尾无须拼接反斜杠)
fileName 文件名称(无需拼接反斜杠)
isDeleteOriginalFile 如果本地已存在相同文件,是否要删除(默认为true)

2. 获取下载apk进度

建议参考这里

/// 在 initState 中调用
FlutterNativeHelper.instance.setMethodCallHandler((call) async {
    if (call.method == FlutterNativeConstant.methodDownloadProgress) {
        if (call.argument is String) {
            final cancelTag = call.argument as String;
        }
    }
});

3. 取消下载

建议参考这里

/// [cancelTag] 在 'initState' 中:
/// 调用 [FlutterNativeHelper.instance.setMethodCallHandler],'method': [FlutterNativeConstant.methodCancelTag],
FlutterNativeHelper.instance.cancelDownload(cancelTag: "$_cancelTag");

4. 仅安装

/// [filePath] apk文件地址,必传
FlutterNativeHelper.instance.installApk(
    filePath: "/data/user/0/$applicationPackageName/files/updateApk/new.apk"
);

5. 打开应用市场当前详情页

简单来说,如果你有指定的应用市场,就传递 targetMarketPackageName 为对应的包名;如果你没有指定的应用市场,但是想让大部分机型都打开厂商应用商店,那么就设置 isOpenSystemMarket 为true

FlutterNativeHelper.instance.openAppMarket(
    targetMarketPackageName: "$targetPackageName", // 指定的应用市场包名,默认为空
    isOpenSystemMarket: true // 如果未指定包名,是否要打开系统自带-应用市场,默认为true
);

二、控制手机发出通知、铃声

1. 播放通知、铃声

/// [assignUri] 指定铃声uri,如不指定,会播放系统默认铃声
///
/// 如需指定铃声,可调用 [FlutterNativeHelper.instance.getSystemRingtoneList],选择心仪的铃声
/// 如连续播放调用多个铃声则会自动中断上一个
/// 返回是否播放成功
val isSuccess = await FlutterNativeHelper.instance.playSystemRingtone(
        assignUri: assignUri);

2. 暂停播放

/// 返回是否暂停成功
val isSuccess = await FlutterNativeHelper.instance.stopSystemRingtone();

3. 是否正在播放

val isPlaying = await FlutterNativeHelper.instance.isPlayingSystemRingtone();

4. 获取系统通知/铃声/警报列表

/// 参数:systemRingtoneType,铃声类型
final List<SystemRingtoneModel> list = await FlutterNativeHelper.instance.getSystemRingtoneList(FlutterNativeConstant.systemRingtoneTypeNotification);
铃声类型 含义
FlutterNativeConstant.systemRingtoneTypeNotification 通知声
FlutterNativeConstant.systemRingtoneTypeAlarm 警报
FlutterNativeConstant.systemRingtoneTypeRingtone 铃声
FlutterNativeConstant.systemRingtoneTypeAll 全部

SystemRingtoneModel

字段 含义
ringtoneTitle 铃声名称
ringtoneUri 铃声Uri

三、其他API

1. 将Uri转换为真实路径

/// 如果出现异常,将返回空字符串
final String realPath = await FlutterNativeHelper.instance.transformUriToRealPath(String? targetUri);

2. 控制设备震动

FlutterNativeHelper.instance.callPhoneToShake();
参数名称 参数意义 是否必传
millSeconds 震动时长,默认为500
amplitude 震动强度 1~255之间

3. 下载文件

/// 该方法与 'downloadAndInstallApk' 参数一致,仅负责下载
///
/// 如果你想预下载apk或其他什么骚操作,可以根据此方法+installApk来完成
/// 返回:文件的真实路径
/// 如需获取下载进度,可参考 第一项第二小节
///
/// 如果,连续多次调用此方法,并且三个参数为完全相同的,那么 Native 端将等待第一个下载完成后才允许继续下载。
final String filePath = await FlutterNativeHelper.instance.downloadFile(fileUrl: "https://xxxx.apk",
    fileDirectory: "updateApk",
    fileName: "new.apk");

4. 进入应用设置详情页

final bool intoResult = await FlutterNativeHelper.instance.intoAppSettingDetail();

5. 获取设备名称

final String deviceName = await FlutterNativeHelper.instance.deviceName;

示例代码

以下是完整的示例代码:

import 'dart:ffi';

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

import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_native_helper/flutter_native_helper.dart';

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

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _platformVersion = 'Unknown';

  String _cancelTag = "";

  [@override](/user/override)
  void initState() {
    super.initState();
    initPlatformState();
    listenNativeMessage();
  }

  /// 监听 Native 端发送的信息
  void listenNativeMessage() {
    FlutterNativeHelper.instance.setMethodCallHandler((call) async {
      switch (call.method) {
        case FlutterNativeConstant.methodDownloadProgress:
          // 获取下载进度
          if (call.arguments is double) {
            final progress = call.arguments as double;
            if (progress < 100) {
              String stringProgress = progress.toString();
              if (stringProgress.length > 5) {
                stringProgress = stringProgress.substring(0, 5);
              }
              EasyLoading.showProgress(progress / 100,
                  status: "下载中 $stringProgress%");
            } else {
              EasyLoading.showSuccess("下载成功");
            }
          }
          break;
        case FlutterNativeConstant.methodCancelTag:
          // 得到 cancelTag
          if (call.arguments is String) {
            _cancelTag = call.arguments as String;
          }
          break;
      }
    });
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlatformState() async {
    String platformVersion;
    try {
      platformVersion = await FlutterNativeHelper.instance.platformVersion ??
          'Unknown platform version';
    } on PlatformException {
      platformVersion = 'Failed to get platform version.';
    }
    if (!mounted) return;

    setState(() {
      _platformVersion = platformVersion;
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      builder: EasyLoading.init(),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Text('Running on: $_platformVersion\n'),
              _buildButton("下载并安装apk", () {
                EasyLoading.show(status: "开始下载");
                FlutterNativeHelper.instance.downloadAndInstallApk(
                    fileUrl: "https://xxxxx.apk",
                    fileDirectory: "updateApk",
                    fileName: "newApk.apk");
              }),
              _buildButton("取消下载", () async {
                if (_cancelTag.isNotEmpty) {
                  await FlutterNativeHelper.instance.cancelDownload(_cancelTag);
                  EasyLoading.dismiss();
                }
              }),
              _buildButton('打开应用市场', () async {}),
              _buildButton("得到铃声列表", () async {
                final List<SystemRingtoneModel> list =
                    await FlutterNativeHelper.instance.getSystemRingtoneList(
                        FlutterNativeConstant.systemRingtoneTypeNotification);
                for (var value in list) {
                  print(
                      "lxlx ringtoneTitle: ${value.ringtoneTitle}, ${value.ringtoneUri}");
                }
              }),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildButton(String text, Function function) {
    return MaterialButton(
      color: Colors.blue,
      child: Text(
        text,
        style: const TextStyle(color: Colors.white),
      ),
      onPressed: () {
        function();
      },
    );
  }

  [@override](/user/override)
  void dispose() {
    FlutterNativeHelper.instance.dispose();
    super.dispose();
  }
}

更多关于Flutter原生功能调用插件flutter_native_helper的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter原生功能调用插件flutter_native_helper的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用flutter_native_helper插件来调用原生功能的一个简单示例。flutter_native_helper是一个用于在Flutter中方便地调用原生(Android和iOS)代码的插件。

1. 添加依赖

首先,你需要在pubspec.yaml文件中添加flutter_native_helper的依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_native_helper: ^x.y.z  # 请替换为最新版本号

然后运行flutter pub get来获取依赖。

2. 配置原生代码

Android

android/app/src/main/kotlin/[your_package_name]/MainActivity.kt(或Java文件)中,你需要定义一个原生方法。例如:

package com.example.yourapp

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant

class MainActivity: FlutterActivity() {
    private val CHANNEL = "com.example.yourapp/channel"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        GeneratedPluginRegistrant.registerWith(flutterEngine)

        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            if (call.method == "showToast") {
                val message = call.argument<String>("message")
                showToast(message)
                result.success(null)
            } else {
                result.notImplemented()
            }
        }
    }

    private fun showToast(message: String?) {
        message?.let {
            Toast.makeText(this, it, Toast.LENGTH_SHORT).show()
        }
    }
}

iOS

ios/Runner/AppDelegate.swift中,你需要配置一个方法通道并处理调用:

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)

    let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
    let channel = FlutterMethodChannel(name: "com.example.yourapp/channel", binaryMessenger: controller)
    channel.setMethodCallHandler({
      (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
      if call.method == "showToast" {
        if let message = call.arguments as? String {
          self.showToast(message: message)
        }
        result(nil)
      } else {
        result(FlutterMethodNotImplemented)
      }
    })
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  private func showToast(message: String) {
    let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
    alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
    let window = UIApplication.shared.keyWindow
    window?.rootViewController?.present(alert, animated: true, completion: nil)
  }
}

3. 在Flutter中调用原生方法

在你的Dart代码中,你可以使用MethodChannel来调用原生方法。首先,确保你导入了flutter_native_helper包(如果它提供了额外的封装,否则直接使用MethodChannel):

import 'package:flutter/services.dart';
import 'package:flutter_native_helper/flutter_native_helper.dart';  // 如果插件提供了封装

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

class MyApp extends StatelessWidget {
  static const platform = const MethodChannel('com.example.yourapp/channel');

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Native Helper Demo'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: _showToast,
            child: Text('Show Toast'),
          ),
        ),
      ),
    );
  }

  Future<void> _showToast() async {
    try {
      await platform.invokeMethod('showToast', <String, dynamic>{'message': 'Hello from Flutter!'});
    } on PlatformException catch (e) {
      print("Failed to invoke: '${e.message}'.");
    }
  }
}

注意事项

  • 确保你已经在AndroidManifest.xmlInfo.plist中配置了必要的权限和配置。
  • 插件的具体使用方法可能会根据版本有所不同,请参考官方文档或仓库中的示例代码。
  • 上述代码只是一个基础示例,实际项目中可能需要更多的错误处理和边界情况考虑。

这个示例展示了如何在Flutter中通过flutter_native_helper(或直接使用MethodChannel)来调用原生功能。希望这对你有所帮助!

回到顶部