Day22 - Flutter - 混合开发(上)

简介: Day22 - Flutter - 混合开发

概述

  • 调用原生功能
  • 嵌入原有项目
  • Flutter模块调试


一、调用原生功能



  • 1.1、Camera某些应用程序可能需要使用移动设备进行拍照或者选择相册中的照片,Flutter官方提供了插件:image_picker
  • 1.1.1、添加依赖
    添加对image_picker的依赖:https://pub.dev/packages/image_picker,在项目的 pubspec.ymal 里面添加下面的依赖即可,然后执行右上角的 Pub get


dependencies:
     image_picker: ^0.6.7+1


  • 1.1.2、平台配置
    对iOS平台,想要访问相册或者相机,需要获取用户的允许:
    依然是修改 info.plist 文件:/ios/Runner/Info.plist
    添加对相册的访问权限:Privacy - Photo Library Usage Description
    添加对相机的访问权限:Privacy - Camera Usage Description


image.png

  • 拓展:其他的权限
  • 相机权限:Privacy - Camera Usage Description 是否允许此App使用你的相机?
  • 相册权限:Privacy - Photo Library Usage Description 是否允许此App访问你的媒体资料库?
  • 通讯录权限:Privacy - Contacts Usage Description 是否允许此App访问你的通讯录?
  • 蓝牙权限:Privacy - Bluetooth Peripheral Usage Description 是否许允此App使用蓝牙?
  • 使用期间定位权限:Privacy - Location When In Use Usage Description 是否允许此App使用定位服务?
  • 始终定位权限:Privacy - Location Always Usage Description 是否允许此App始终使用定位服务?
  • 语音转文字权限:Privacy - Speech Recognition Usage Description 是否允许此App使用语音识别?
  • 日历权限:Privacy - Calendars Usage Description 是否允许此App使用日历?
  • 健康—读取数据: Privacy - Health Share Usage Description 是否允许此App读取健康数据?
  • 健康—写入数据: Privacy - Health Share Usage Description 是否允许此App写入健康数据?
  • 读取HomeKit: Privacy - HomeKit Usage Description 是否允许此App访问HomeKit?
  • 麦克风:Privacy - Microphone Usage Description 是否允许此App访问麦克风?
  • 提醒事项: Privacy - Reminders Usage Description 是否允许此App访问提醒事项?
  • 运动与健身: Privacy - Motion Usage Description 是否允许此App访问运动与健身?
  • 面部ID权限: Privacy - Face ID Usage Description 是否允许此App访问Face ID?


之后选择相册或者访问相机时,会弹出如下的提示框:

image.png


image.png


1.1.3、代码实现


image_picker 的核心代码是 getImage 方法:

可以传入数据源、图片的大小、质量、前置后置摄像头等

数据源是必传参数:ImageSource 枚举类型: camera:相机gallery:相册

Future<PickedFile> getImage({
   @required ImageSource source,
   double maxWidth,
   double maxHeight,
   int imageQuality,
   // 默认后置摄像头
   CameraDevice preferredCameraDevice = CameraDevice.rear,
}) {
   return platform.pickImage(
      source: source,
      maxWidth: maxWidth,
      maxHeight: maxHeight,
      imageQuality: imageQuality,
      preferredCameraDevice: preferredCameraDevice,
   );
}

案例演练:

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
class JKCameraScreen extends StatefulWidget {
   @override
   _JKCameraScreenState createState() => _JKCameraScreenState();
}
class _JKCameraScreenState extends State<JKCameraScreen> {
   PickedFile _imageFile;
   final ImagePicker _picker = ImagePicker();
   @override
   Widget build(BuildContext context) {
        return Center(
           child: Column(
              children: [
                 RaisedButton(
                    child: Text('选择一个相册'),
                    onPressed: _pickImage
                 ),
                 _imageFile == null ? Text('请选择一张照片') : Image.file(File(_imageFile.path))
              ],
           ),
        );
   }
   void _pickImage() async {
        print('选择相册');
        PickedFile pickedFile = await _picker.getImage(source: ImageSource.gallery);
        setState(() {
            _imageFile = pickedFile;
        });
   }
}


image.png


image.png


1.2、电池信息

某些原生的信息,如果没有很好的插件,我们可以通过、platform channels(平台通道) 来获取信息。

  • 1.2.1、平台通过介绍平台通过是如何工作的呢?
  • 消息使用platform channels(平台通道)在客户端(UI)和宿主(平台)之间传递;
  • 消息和响应以异步的形式进行传递,以确保用户界面能够保持响应;


image.png


调用过程大致如下:

  • 1.客户端(Flutter端)发送与方法调用相对应的消息
  • 2.平台端(iOS、Android端)接收方法,并返回结果;
  • iOS端通过FlutterMethodChannel做出响应;
  • Android端通过MethodChannel做出响应;

Flutter、iOS、Android端数据类型的对应关系:


image.png

  • 1.2.2、创建测试项目我们这里创建一个获取电池电量信息的项目,分别通过iOS和Android原生代码来获取对应的信息:


  • 创建方式一:默认创建方式,目前默认创建的Flutter项目,对应iOS的编程语言是Swift,对应Android的编程语言是kotlin


flutter create batterylevel
  • 创建方式二:指定编程语言,如果我们希望指定编程语言,比如iOS编程语言为Objective-C,Android的编程语言为Java


flutter create -i objc -a java batterylevel2
  • 提示:i代表 iOSa 代表 android


  • 1.2.3、写Dart代码在Dart代码中,我们需要创建一个MethodChannel对象:
  • 创建该对象时,需要传入一个name,该name是区分多个通信的名称
  • 可以通过调用该对象的invokeMethod来给对应的平台发送消息进行通信
  • 该调用是异步操作,需要通过await获取then回调来获取结果


import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
        return MaterialApp(
            // 启动要显示的界面
            home: HomePage(),
        );
    }
}
class HomePage extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
       return Scaffold(
           appBar: AppBar(
              title: Text("原生电池的调用"),
           ),
           body: JKBatteryLevel(),
       );
   }
}
class JKBatteryLevel extends StatefulWidget {
    @override
    _JKBatteryLevelState createState() => _JKBatteryLevelState();
}
class _JKBatteryLevelState extends State<JKBatteryLevel> {
     // 定义一个平台通道
     static const platform1 = const MethodChannel('com.jk/battery');
     int _batterylevel = 0;
     @override
     Widget build(BuildContext context) {
        return Center(
           child: Column(
              children: [
                  RaisedButton(
                       child: Text('获取剩余电量'),
                       onPressed: _buildLevelInfo
                  ),
                  Text('电量:${_batterylevel}')
              ],
           ),
        );
    }
    void _buildLevelInfo() async {
         // 调用原生的电池信息
         final result = await platform1.invokeMethod('getBatteryInfo');
          setState(() {
              _batterylevel = result;
          });
    }
}
  • 当我们通过 platform.invokeMethod调用对应平台方法时,需要在对应的平台实现其操作:
    iOS 中可以通过 Objective-CSwift 来实现
    Android 中可以通过 Java 或者 Kotlin 来实现


  • 1.2.4、编写iOS代码
  • <1>、Swift 代码,在 AppDelegate.swift 里面写代码


import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    override func application(
        _ application: UIApplication,
       didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
       // 实现获取电量信息的功能
       // 1、获取FlutterViewController
       let flutterController: FlutterViewController = window.rootViewController as! FlutterViewController
       // 2、创建 FlutterMethodChannel
       /**
         name:static const platform1 = const MethodChannel('com.jk/battery'); 的 com.jk/battery,名字自己定义: 域名/名字
         binaryMessenger:  二进制消息
        */
       let channel = FlutterMethodChannel(name: "com.jk/battery", binaryMessenger: flutterController.binaryMessenger);
       // 3.监听channnel方法
       channel.setMethodCallHandler { (call: FlutterMethodCall, result: @escaping FlutterResult) in
           guard call.method == "getBatteryInfo" else {
                // 找不到该方法
                result(FlutterMethodNotImplemented)
                return;
           }
           let device = UIDevice.current
           // 电池电量的探测,设置为true,才能更好的获取电量
           device.isBatteryMonitoringEnabled = true
           if device.batteryState == .unknown {
                result(FlutterError(code: "Unknown", message: "Battery is unknown", details: nil))
            } else {
                result(Int(device.batteryLevel * 100))
            }
        }
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
   }
}


image.png


image.png


  • <2>、OC 代码


#import "AppDelegate.h"
#import "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 1.获取FlutterViewController(是应用程序的默认Controller)
    FlutterViewController *flutterController = (FlutterViewController *)self.window.rootViewController;
    // 2.获取MethodChannel(方法通道)
    FlutterMethodChannel *batteryChannel = [FlutterMethodChannel methodChannelWithName:@"com.jk/battery" binaryMessenger:flutterController.binaryMessenger];
    // 3.监听方法调用(会调用传入的回调函数)
    __weak typeof(self) weakSelf = self;
    [batteryChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult  _Nonnull result) {
        // 3.1.判断是否是getBatteryInfo的调用
        if ([@"getBatteryInfo" isEqualToString:call.method]) {
            // 1.iOS中获取信息的方式
            int batteryLevel = [weakSelf getBatteryLevel];
            // 2.如果没有获取到,那么返回给Flutter端一个异常
            if (batteryLevel == -1) {
                result([FlutterError errorWithCode:@"UNAVAILABLE"
                        message:@"Battery info unavailable"
                        details:nil]);
            } else {
                // 3.通过result将结果回调给Flutter端
                result(@(batteryLevel));
            }
        } else {
             // 3.2.如果调用的是getBatteryInfo的方法, 那么通过封装的另外一个方法实现回调
            result(FlutterMethodNotImplemented);
        }
     }];
     [GeneratedPluginRegistrant registerWithRegistry:self];
     // Override point for customization after application launch.
     return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
- (int)getBatteryLevel {
    // 获取信息的方法
    UIDevice* device = UIDevice.currentDevice;
    device.batteryMonitoringEnabled = YES;
    if (device.batteryState == UIDeviceBatteryStateUnknown) {
         return -1;
    } else {
         return (int)(device.batteryLevel * 100);
    }
}
@end
  • 1.2.5、编写 Android 代码
  • <1>、Ktolin 代码


package com.example.batterylevel
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.Build
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
class MainActivity: FlutterActivity() {
   private val CHANNEL = "com.jk/battery"
   override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
       super.configureFlutterEngine(flutterEngine)
       // 1.创建MethodChannel对象
       val methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
       // 2.添加调用方法的回调
       methodChannel.setMethodCallHandler { call, result ->
           if (call.method == "getBatteryInfo") {
                // 2.1.1.调用另外一个自定义方法回去电量信息
                val batteryLevel = getBatteryLevel()
                // 2.1.2. 判断是否正常获取到
                if (batteryLevel != -1) {
                     // 获取到返回结果
                     result.success(batteryLevel)
                } else {
                     // 获取不到抛出异常
                     result.error("UNAVAILABLE", "Battery level not available.", null)
                }
           } else {
                // 2.2.如果调用的方法是getBatteryInfo,那么正常执行
                result.notImplemented()
           }
       }
    }
    private fun getBatteryLevel(): Int {
        val batteryLevel: Int
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
           val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager
           batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
        } else {
           val intent = ContextWrapper(applicationContext).registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
           batteryLevel = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
        }
        return batteryLevel
    }
}


image.png

image.png


目录
相关文章
|
4月前
|
移动开发 前端开发 JavaScript
探究移动端混合开发技术:React Native、Weex、Flutter的比较与选择
移动端混合开发技术在移动应用开发领域日益流行,为开发者提供了更高效的跨平台开发方案。本文将比较三种主流混合开发技术:React Native、Weex和Flutter,从性能、生态系统和开发体验等方面进行评估,以帮助开发者在选择适合自己项目的技术时做出明智的决策。
|
4月前
|
移动开发 前端开发 weex
React Native、Weex、Flutter 混合开发技术的比较与选择
移动应用已经成为人们日常生活中不可或缺的一部分,而混合开发技术也随之崛起并逐渐成为主流。本文将比较 React Native、Weex 和 Flutter 三种混合开发技术,并探讨它们各自的优缺点,以及如何根据项目需求做出选择。
60 1
|
4月前
|
移动开发 前端开发 weex
移动端混合开发技术:React Native、Weex、Flutter 之争
在移动应用开发领域,React Native、Weex 和 Flutter 是备受关注的混合开发技术。本文将对它们进行全面比较与评估,以帮助开发者做出明智的选择。我们将从开发生态、性能、跨平台能力和易用性等方面进行比较,为读者提供全面的参考和指导。
|
4月前
|
移动开发 Dart 前端开发
移动端混合开发技术:React Native、Weex、Flutter的比较与选择
移动应用的开发已经成为现代社会中的重要一环。本文将比较并评估三种主流的移动端混合开发技术:React Native、Weex和Flutter。通过对它们的特点、优势和劣势的分析,帮助开发者在选择适合自己项目的技术方案时做出明智的决策。
|
4月前
|
移动开发 开发框架 前端开发
移动端混合开发技术探析:React Native、Weex、Flutter的比较与选择
随着移动应用开发的高速发展,混合开发技术成为了一种备受关注的选择。本文将对移动端混合开发技术中的React Native、Weex和Flutter进行比较与探讨,分析它们在性能、开发体验、生态系统和跨平台支持等方面的差异,以及如何根据项目需求进行选择。
71 1
|
5月前
|
Dart 开发工具 Android开发
Flutter混合开发:Android中如何启动Flutter
Flutter混合开发:Android中如何启动Flutter 如果你想在你的Android应用中使用Flutter,则需要遵循以下步骤:
|
8月前
|
Dart 开发工具 Android开发
Flutter与iOS原生混合开发
Flutter与iOS原生混合开发
352 2
|
Dart Android开发
Flutter 之原生混合开发
Flutter 之原生混合开发
425 0
Flutter 之原生混合开发
|
Dart Java API
Flutter 混合开发(下)
某些应用程序可能需要使用移动设备进行拍照或者选择相册中的照片,Flutter官方提供了插件:image_picker
571 0
Flutter 混合开发(下)
|
Dart Java Android开发
Flutter 混合开发(上)
某些应用程序可能需要使用移动设备进行拍照或者选择相册中的照片,Flutter官方提供了插件:image_picker
280 0
Flutter 混合开发(上)