Flutter原生相机功能插件lecle_native_camera的使用

Flutter原生相机功能插件lecle_native_camera的使用

lecle_native_camera 是一个用于在Flutter项目中打开设备摄像头以拍摄照片或视频(在Android平台上也可以选择照片)并在Android和iOS平台上获取文件路径和文件类型的插件。

Android

AndroidManifest.xml 文件中添加以下属性:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          package="your package...">

添加以下权限:

    <uses-feature android:name="android.hardware.camera.any"
        android:required="true" />
    <uses-feature android:name="android.hardware.camera.autofocus"
        android:required="false" />

    <uses-permission android:name="android.permission.CAMERA"  
        android:required="true"
        android:requiredFeature="true" />

    <uses-permission android:name="android.permission.FLASHLIGHT" />
    <uses-feature android:name="android.hardware.camera.flash" android:required="false"
        tools:targetApi="eclair" />

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

android/app/src/main/res 目录下创建 xml 文件夹,并添加以下内容到 file_paths.xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="external_files"
        path="." />
</paths>

创建自己的 FileProvider 并定义自己的路径,然后将其添加到 AndroidManifest.xml 文件中:

<provider android:name="androidx.core.content.FileProvider"
          android:authorities="vn.lecle.native_camera.fileprovider"
          android:exported="false" android:grantUriPermissions="true">
    <meta-data android:name="android.support.FILE_PROVIDER_PATHS" 
               android:resource="@xml/file_paths" />
</provider>

iOS

Info.plist 文件中添加以下内容:

<key>NSCameraUsageDescription</key>
<string>我们的应用需要访问您的摄像头</string>

<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) 需要访问麦克风以录制视频和音频</string>

<key>NSPhotoLibraryAddUsageDescription</key>
<string>$(PRODUCT_NAME) 需要保存照片到您的相册</string>

<key>NSPhotoLibraryUsageDescription</key>
<string>$(PRODUCT_NAME) 需要访问您的照片</string>

<key>NSBonjourServices</key>
<array>
    <string>_dartobservatory._tcp</string>
</array>

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <true/>
</dict>

如何使用

只需调用 LecleNativeCamera 类中的 openNativeCamera 方法即可打开原生相机以拍摄照片或视频(在Android平台上也可以选择照片),该方法将返回捕获文件的路径和文件类型。

返回的数据将被转换为 FileData 对象,您可以使用此对象轻松获取文件路径和文件类型。

属性

以下是 openNativeCamera 方法中的属性及其适用平台:

属性 Android iOS
fileProviderPath X
imageExtension X X
videoExtension X X
fileName X X
androidOptionSheetTitle X
canPickFile X
videoQuality X X
imageQuality X X
imageWidth X
imageHeight X
customSaveFolder X
saveFolder X

示例

以下是一个完整的示例代码,展示了如何使用 lecle_native_camera 插件来打开原生相机并处理拍摄的照片或视频。

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:lecle_native_camera/constants/enums/enums.dart';
import 'package:lecle_native_camera/lecle_native_camera.dart';
import 'package:lecle_native_camera/models/file_data_model.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:video_player/video_player.dart';

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  File? imageFile;
  File? videoFile;
  VideoPlayerController? _controller;
  bool _isPlaying = false;

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

  [@override](/user/override)
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }

  void _requestPermissions() async {
    await [Permission.camera, Permission.microphone, Permission.storage]
        .request();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: SingleChildScrollView(
        child: SizedBox(
          width: MediaQuery.of(context).size.width,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            mainAxisSize: MainAxisSize.max,
            children: [
              Visibility(
                visible: imageFile != null,
                child: imageFile != null
                    ? Image.file(imageFile!)
                    : const SizedBox.shrink(),
              ),
              Visibility(
                visible: videoFile != null && _controller != null,
                child: videoFile != null && _controller != null
                    ? AspectRatio(
                        child: VideoPlayer(_controller!),
                        aspectRatio: _controller!.value.aspectRatio,
                      )
                    : const SizedBox.shrink(),
              ),
              const SizedBox(height: 32.0),
              ElevatedButton(
                onPressed: () async {
                  if (videoFile == null) {
                    return;
                  }

                  _controller?.value.isPlaying ?? false
                      ? await _controller?.pause()
                      : await _controller?.play();

                  if (_controller?.value.isPlaying ?? false) {
                    setState(() {
                      _isPlaying = true;
                    });
                  } else {
                    setState(() {
                      _isPlaying = false;
                    });
                  }
                },
                child: Icon(
                  _isPlaying ? Icons.pause : Icons.play_arrow,
                ),
              ),
              ElevatedButton(
                onPressed: () {
                  LecleNativeCamera.openNativeCamera(
                    fileProviderPath: 'vn.lecle.native_camera.fileprovider', // 这必须与您在AndroidManifest文件中定义的自定义路径相同
                    imageExtension: ImageExtension.jpeg,
                    videoQuality: VideoQuality.typeHigh,
                    videoExtension: VideoExtension.mov,
                    imageQuality: 100,
                    imageWidth: 2160,
                    imageHeight: 3804,
                    androidOptionSheetTitle: 'Choose an option',
                    canPickFile: true,
                    fileName: 'your_custom_file_name',
                    customSaveFolder: 'Test Folder',
                  ).then(
                    (value) async {
                      if (value != null) {
                        print('$value');

                        if (value.fileType == FileType.image && value.filePath != null) {
                          setState(() {
                            imageFile = File(value.filePath!);
                            imageFile!.length().then((value) {
                              print('File size ::: $value');
                            });
                            videoFile = null;
                            _controller = null;
                          });
                        } else if (value.fileType == FileType.video && value.filePath != null) {
                          setState(() {
                            videoFile = File(value.filePath!);
                            videoFile!.length().then((value) {
                              print('File size ::: $value');
                            });
                            imageFile = null;
                            _controller = VideoPlayerController.file(videoFile!);
                            _controller!.initialize().then(
                              (value) {
                                setState(() {});
                                _controller!.addListener(() {
                                  if (_controller?.value.position == _controller?.value.duration) {
                                    setState(() {
                                      _isPlaying = false;
                                    });
                                  }
                                });
                              },
                            );
                          });
                        }
                      }
                    },
                  );
                },
                child: const Text('Open native camera'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

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

1 回复

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


lecle_native_camera 是一个 Flutter 插件,用于在 Flutter 应用中集成原生相机功能。它允许你访问设备的摄像头,并捕获照片或视频。以下是如何使用 lecle_native_camera 插件的基本步骤:

1. 添加依赖

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

dependencies:
  flutter:
    sdk: flutter
  lecle_native_camera: ^1.0.0  # 请使用最新的版本号

然后运行 flutter pub get 来安装依赖。

2. 配置权限

为了使用相机功能,你需要在 AndroidManifest.xmlInfo.plist 中添加相应的权限。

Android

android/app/src/main/AndroidManifest.xml 文件中添加以下权限:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

iOS

ios/Runner/Info.plist 文件中添加以下键值对:

<key>NSCameraUsageDescription</key>
<string>We need access to your camera to take photos.</string>
<key>NSMicrophoneUsageDescription</key>
<string>We need access to your microphone to record video.</string>

3. 初始化相机

在你的 Flutter 应用中,你可以通过以下步骤初始化相机:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CameraScreen(),
    );
  }
}

class CameraScreen extends StatefulWidget {
  @override
  _CameraScreenState createState() => _CameraScreenState();
}

class _CameraScreenState extends State<CameraScreen> {
  late NativeCameraController _cameraController;

  @override
  void initState() {
    super.initState();
    _initializeCamera();
  }

  Future<void> _initializeCamera() async {
    _cameraController = NativeCameraController();
    await _cameraController.initialize();
  }

  @override
  void dispose() {
    _cameraController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Native Camera Example'),
      ),
      body: Center(
        child: NativeCameraPreview(controller: _cameraController),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          final imagePath = await _cameraController.captureImage();
          print('Image saved at: $imagePath');
        },
        child: Icon(Icons.camera_alt),
      ),
    );
  }
}

4. 捕获照片

在上面的代码中,_cameraController.captureImage() 方法用于捕获照片。捕获的照片将保存到设备的存储中,并返回文件的路径。

5. 捕获视频

如果你想捕获视频,可以使用 _cameraController.captureVideo() 方法。同样,视频文件将保存到设备的存储中,并返回文件的路径。

floatingActionButton: FloatingActionButton(
  onPressed: () async {
    final videoPath = await _cameraController.captureVideo();
    print('Video saved at: $videoPath');
  },
  child: Icon(Icons.videocam),
),

6. 处理权限

在 Android 和 iOS 上,你需要确保应用有权限访问相机。你可以使用 permission_handler 插件来请求和检查权限。

import 'package:permission_handler/permission_handler.dart';

Future<void> _checkPermissions() async {
  var status = await Permission.camera.status;
  if (!status.isGranted) {
    await Permission.camera.request();
  }
}

initState 中调用 _checkPermissions() 以确保应用有权限访问相机。

7. 处理相机方向

你还可以通过 _cameraController.setFlashMode()_cameraController.setFocusMode() 等方法调整相机的设置。

8. 处理相机生命周期

确保在 dispose 方法中释放相机资源,以避免内存泄漏。

@override
void dispose() {
  _cameraController.dispose();
  super.dispose();
}

9. 处理异常

在实际应用中,你应该捕获并处理可能出现的异常,例如相机初始化失败或权限被拒绝。

try {
  await _cameraController.initialize();
} catch (e) {
  print('Failed to initialize camera: $e');
}
回到顶部