Web调用设备信息和服务

12147

device_info_plus

用于获取当前设备信息。

  1. //pubspec.yaml 中声明 device_info_plus
  2. dependencies:
  3. device_info_plus: ^3.2.2
  4. //DeviceInfoUtil.dart 中引入包
  5. import 'package:device_info_plus/device_info_plus.dart';
  6. //实例化DeviceInfoPlugin,获取特定平台的设备信息
  7. getDeviceInfo() async {
  8. if (Platform.isAndroid) {
  9. return _readAndroidBuildData(await deviceInfoPlugin.androidInfo);
  10. } else if (...) {
  11. //do something
  12. }
  13. }
  14. Map<String, dynamic> _readAndroidBuildData(AndroidDeviceInfo build) {
  15. return <String, dynamic>{
  16. 'version.securityPatch': build.version.securityPatch,
  17. 'version.sdkInt': build.version.sdkInt,
  18. 'version.release': build.version.release,
  19. 'version.previewSdkInt': build.version.previewSdkInt,
  20. ...
  21. };
  22. }
  23. //项目初始化的时候获取设备信息
  24. //代码来源:/jianghuAppBrowser/jianghuBrowser/lib/layout/JianghuConfigHandler.dart
  25. Future<void> jianghuInit() async {
  26. Constants.deviceInfo ??= await DeviceInfoUtil().getDeviceInfo();
  27. }

package_info

用于查询有关应用程序包的信息。

  1. //pubspec.yaml 中声明 package_info
  2. dependencies:
  3. package_info:
  4. //main.dart中引入package_info
  5. import 'package:package_info/package_info.dart';
  6. //使用
  7. PackageInfo packageInfo = await PackageInfo.fromPlatform();
  8. String appName = packageInfo.appName;
  9. String packageName = packageInfo.packageName;
  10. String version = packageInfo.version;
  11. String buildNumber = packageInfo.buildNumber;

preferences

用于持久化简单数据数据存储。

  1. //pubspec.yaml 中声明 prefs
  2. dependencies:
  3. prefs: ^3.4.0+1
  4. //main.dart中引入prefs
  5. import 'package:prefs/prefs.dart';
  6. //使用
  7. await Prefs.init();
  8. Constants.defaultHostUrl = Prefs.getString("homeUrl");

权限申请

用于请求权限并检查其状态。

  1. //pubspec.yaml 中声明
  2. dependencies:
  3. permission_handler: ^9.2.0
  4. //引入
  5. import 'package:permission_handler/permission_handler.dart';
  6. //使用
  7. PermissionStatus storageStatus = await Permission.storage.status;
  8. if (storageStatus != PermissionStatus.granted) {
  9. throw '无法存储图片,请先授权!';
  10. }

复制

用于将文本复制到剪贴板并从剪贴板粘贴。

  1. //pubspec.yaml 中声明
  2. dependencies:
  3. clipboard: ^0.1.3
  4. //引入
  5. import 'package:clipboard/clipboard.dart';
  6. //复制到剪贴板
  7. FlutterClipboard.copy('hello flutter friends').then(( value ) => print('copied'));
  8. //从剪贴板粘贴
  9. FlutterClipboard.paste().then((value) {
  10. // Do what ever you want with the value.
  11. setState(() {
  12. field.text = value;
  13. pasteValue = value;
  14. });
  15. });

文件选择

用于查找文件系统上常用位置。

  1. //pubspec.yaml 中声明
  2. dependencies:
  3. path_provider: ^2.0.9
  4. //引入
  5. import 'package:path_provider/path_provider.dart' as path_provider;
  6. //使用
  7. final Directory tempDir = await path_provider.getTemporaryDirectory();
  8. final Directory appDocumentsDir = await path_provider.getApplicationDocumentsDirectory();
  9. final Directory? downloadsDir = await path_provider.getDownloadsDirectory();

通知栏

用于显示本地通知。

  1. //pubspec.yaml 中声明
  2. dependencies:
  3. flutter_local_notifications: ^9.6.0
  4. //引入
  5. import 'package:flutter_local_notifications/flutter_local_notifications.dart';
  6. //封装
  7. class Notification {
  8. final FlutterLocalNotificationsPlugin np = FlutterLocalNotificationsPlugin();
  9. // main 初始化
  10. init() async {
  11. var android = const AndroidInitializationSettings("@mipmap/ic_launcher");
  12. var ios = const IOSInitializationSettings();
  13. await np.initialize(InitializationSettings(android: android, iOS: ios));
  14. }
  15. //发送消息
  16. void send(String title, String body, {int? notificationId, String? params}) {
  17. var androidDetails = const AndroidNotificationDetails(
  18. 'channelId',
  19. 'channelName',
  20. importance: Importance.max,
  21. priority: Priority.high,
  22. );
  23. //ios配置
  24. var iosDetails = const IOSNotificationDetails();
  25. var details = NotificationDetails(android: androidDetails, iOS: iosDetails);
  26. np.show(notificationId ?? DateTime.now().millisecondsSinceEpoch >> 10,
  27. title, body, details,
  28. payload: params);
  29. }
  30. }
  31. //使用
  32. await notification.init();
  33. notification.send("title", "content", params: json.encode(params));

音频播放

  • 音乐播放器后台播放的入口点
  1. //main.dart
  2. @pragma('vm:entry-point')
  3. Future<void> playerBackgroundService() async {
  4. WidgetsFlutterBinding.ensureInitialized();
  5. print("start playerBackgroundService");
  6. runBackgroundService(
  7. config: const Config(pauseWhenTaskRemoved: false, enableCache: false),
  8. imageLoadInterceptor: BackgroundInterceptors.loadImageInterceptor,
  9. playUriInterceptor: BackgroundInterceptors.playUriInterceptor,
  10. playQueueInterceptor: QuietPlayQueueInterceptor(),
  11. );
  12. }

@pragma('vm:entry-point') 是一个Dart语言提供的元数据注解(Metadata Annotation)。它的作用是告诉Dart编译器,这些被注解的方法、变量、常量等应该被编译器当做程序的入口点(Entry Point)来生成可执行文件。

在Dart中,当我们运行一个程序时,Dart虚拟机需要知道程序的入口点(即从哪个方法开始执行),然后才能开始执行完整的程序。但有时我们的程序中可能包含了很多不是入口点的方法和变量,如果不使用@pragma('vm:entry-point')注解,编译器可能会把这些打上“无用代码”标签,从而在编译或者优化时被标记为需要被移除的无用代码。这样的话,这些方法或变量就不能作为程序的入口点了。

  • 播放
  1. //方法定义:/jianghuAppBrowser/jianghuBrowser/lib/player/player_handler.dart
  2. void playAudio(BuildContext context, Map result) {
  3. //do something...
  4. }
  5. //引入包
  6. import 'package:music_player/music_player.dart';
  7. //实现
  8. /jianghuAppBrowser/jianghuBrowser/lib/player/music_context.dart

转发

转发到其他 App

  • 分享信息到其他APP方法定义
  1. //代码来源:/jianghuAppBrowser/jianghuBrowser/lib/layout/WebViewHandler.dart
  2. Future<void> shareMsgToOtherApp(Map<dynamic, dynamic> result, BuildContext context) async {
  3. bool isText = result['msg']['messageContentType'] == 'text';
  4. String msgContent = result['msg']['messageContent'];
  5. if (Constants.hostUri == null) {
  6. return;
  7. }
  8. if (!isText) {
  9. Map msgContentMap = jsonDecode(msgContent);
  10. String fileUrl = "${Constants.hostUri!.scheme}://${Constants.hostUri!.host}:${Constants.hostUri!.port}/${Constants.appId.value}/upload${msgContentMap['downloadPath']}";
  11. String filename = msgContentMap['filename'];
  12. String? fileFullPath = await DownloadUtil().downloadFile(fileUrl, filename, onReceiveProgress: (count, total) {
  13. Utils.webToast("正在保存图片${(count / total * 100).toStringAsFixed(0)}%", 'loading');
  14. });
  15. if (fileFullPath == null) {
  16. return;
  17. }
  18. Constants.isSkipAppResumed = true;
  19. OpenFilex.share(fileFullPath);
  20. } else {
  21. FlutterClipboard.copy(msgContent).then((value) {
  22. EasyLoading.showToast('内容已复制: $msgContent');
  23. });
  24. Constants.isSkipAppResumed = true;
  25. OpenFilex.shareText(msgContent);
  26. }
  27. }
  • 安卓端功能实现
  1. //参考
  2. /jianghuAppBrowser/jianghuBrowser/android/app/src/main/kotlin/org/fsll/jianghu_browser/MainActivity.kt
  3. //配置:/jianghuAppBrowser/jianghuBrowser/android/app/src/main/AndroidManifest.xml
  4. <intent-filter>
  5. <action android:name="android.intent.action.SEND" />
  6. <category android:name="android.intent.category.DEFAULT" />
  7. <data android:mimeType="image/*" />
  8. </intent-filter>
  9. <intent-filter>
  10. <action android:name="android.intent.action.SEND" />
  11. <category android:name="android.intent.category.DEFAULT" />
  12. <data android:mimeType="video/*" />
  13. </intent-filter>
  14. <intent-filter>
  15. <action android:name="android.intent.action.SEND" />
  16. <category android:name="android.intent.category.DEFAULT" />
  17. <data android:mimeType="text/*" />
  18. </intent-filter>
  19. <intent-filter>
  20. <action android:name="android.intent.action.SEND" />
  21. <category android:name="android.intent.category.DEFAULT" />
  22. <data android:mimeType="application/*" />
  23. </intent-filter>
  • ios端功能实现
  1. 待补充

接收转发

  • 注册Android原生事件,接受其他app的分享
  1. // 代码来源:/jianghuAppBrowser/jianghuBrowser/lib/layout/JianghuConfigHandler.dart
  2. void createEventChannelListen() {
  3. Constants.channel = const EventChannel('share_from_other_app');
  4. Constants.shareStreamSubscription = Constants.channel!.receiveBroadcastStream().listen((dynamic event) async {
  5. if (event.runtimeType.toString() == 'String' && (event as String).contains('reg done')) {
  6. } else {
  7. print("share_from_other_app event ${event.keys} fileName:${event['fileName']} fileType:${event['fileType']}");
  8. try {
  9. // Uint8List temp = (event['bytes'].buffer as ByteBuffer).asUint8List();
  10. // // 转换为 Uint8List
  11. // debugPrint('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> share_from_other_app Uint8List: ${temp}');
  12. // 测试写入文件,回头删掉
  13. Directory savePath = Directory("${(await getExternalCacheDirectories())!.first.path}/${Constants.appId.value}");
  14. if (!savePath.existsSync()) {
  15. savePath.createSync();
  16. }
  17. String fileName = event['fileName'];
  18. if (!fileName.contains('.')) {
  19. if (event['fileType'].contains('image/')) {
  20. fileName = "$fileName.jpg";
  21. }
  22. if (event['fileType'].contains('video/')) {
  23. fileName = "$fileName.mp4";
  24. }
  25. if (event['fileType'].contains('audio/')) {
  26. fileName = "$fileName.mp3";
  27. }
  28. }
  29. String fullPath = "${savePath.path}/$fileName";
  30. File file = File(fullPath);
  31. var raf = file.openSync(mode: FileMode.write);
  32. await raf.writeFrom(event['bytes']);
  33. await raf.close();
  34. // 暂存流,当用户点击某个聊天/好友/群组的时候,发送流到web端,进行流的上传并且转发
  35. FileUtil.sendFileToWebByStream(
  36. actionTime: "${DateTime.now().millisecondsSinceEpoch}", filePath: fullPath, fileName: fileName, delete: true);
  37. } catch (error) {
  38. debugPrint('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> share_from_other_app error: $error');
  39. }
  40. }
  41. // TODO 接受的内容发送到webview, 便于发送到某个用户
  42. }, onError: (dynamic error) {
  43. debugPrint('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> share_from_other_app Received error: ${error.message}');
  44. }, cancelOnError: true);
  45. }
  • 安卓端功能实现
  1. //参考
  2. /jianghuAppBrowser/jianghuBrowser/android/app/src/main/kotlin/org/fsll/jianghu_browser/MainActivity.kt
  3. //注册通道,eventSink 给flutter端发送信息
  4. EventChannel(binaryMessenger, "share_from_other_app").apply
  5. //流程
  6. onNewIntent -> handlerSendIntent -> 使用eventSink flutter端发送信息 -》flutter收到消息,给web端发消息,-> web 弹窗选择好友或房间 -》 回调给flutter =》 如果是图片则保存到本地,如果是文字直接发送 -》web端接收到消息,sendmessage

IOS 安卓端功能实现

  1. 待补充

保存图片到相册

用于将图片保存到图库中。

  1. //pubspec.yaml 中声明
  2. dependencies:
  3. image_gallery_saver: ^1.7.1
  4. //引入
  5. import 'package:image_gallery_saver/image_gallery_saver.dart';
  6. //使用
  7. final saveResult = await ImageGallerySaver.saveImage(Uint8List.fromList(File(fullPath).readAsBytesSync()),
  8. name: "${DateTime.now().millisecondsSinceEpoch}_${result['name']}", isReturnImagePathOfIOS: Platform.isIOS);
  9. if (saveResult == null || saveResult == '') {
  10. Utils.webToast("保存失败", 'fail');
  11. } else {
  12. Utils.webToast("保存到相册成功", 'success');
  13. }