Explorar el Código

update: 修改CameraView实现方式

hwh97 hace 5 años
padre
commit
09cca94e31

+ 85 - 35
android/src/main/kotlin/com/i2edu/flutter_ali_camera/AliCameraView.kt

@@ -25,30 +25,96 @@ import com.aliyun.svideo.sdk.external.struct.encoder.VideoCodecs
 import com.aliyun.svideo.sdk.external.struct.recorder.CameraParam
 import com.aliyun.svideo.sdk.external.struct.recorder.CameraType
 import com.aliyun.svideo.sdk.external.struct.recorder.MediaInfo
+import io.flutter.plugin.common.BinaryMessenger
+import io.flutter.plugin.common.MethodCall
 import io.flutter.plugin.common.MethodChannel
 import io.flutter.plugin.platform.PlatformView
 import java.io.File
 import java.lang.Exception
 
-class AliCameraView(private val context: Context, private val channel: MethodChannel) : PlatformView {
+class AliCameraView(private val context: Context, private val binaryMessenger: BinaryMessenger, id: Int, param: Any?) : PlatformView, MethodChannel.MethodCallHandler {
     private val TAG = "AliCameraView"
     var surfaceView: SurfaceView? = null
     var frameLayout: FrameLayout? = null
 
+    private var methodChannel: MethodChannel? = null
     private var recorder: AliyunIRecorder? = null
     private val mainHandler: Handler = Handler(Looper.getMainLooper())
 
-    private fun setUpView(context: Context) {
-        if (frameLayout == null) {
-            frameLayout = FrameLayout(context)
-            frameLayout?.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
-            surfaceView = SurfaceView(context)
-            surfaceView?.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
-            frameLayout?.addView(surfaceView)
+    init {
+        frameLayout = FrameLayout(context)
+        frameLayout?.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+        surfaceView = SurfaceView(context)
+        surfaceView?.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+        frameLayout?.addView(surfaceView)
+
+        methodChannel = MethodChannel(binaryMessenger, "com.i2edu.cameraLib/camera_view_$id")
+        methodChannel?.setMethodCallHandler(this)
+    }
+
+    override fun getView(): View {
+        return frameLayout!!
+    }
+
+    override fun dispose() {
+        if (frameLayout != null) {
+            frameLayout?.removeView(surfaceView)
+            frameLayout = null
+        }
+        if (surfaceView != null) {
+            surfaceView = null
+        }
+        onDestroy()
+    }
+
+    override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
+        when (call.method) {
+            "create" -> {
+                val recordOption: Map<String, Any> = call.argument<Map<String, Any>>("recordOption")!!
+                setUpCameraView(recordOption = recordOption)
+                result.success(true)
+            }
+            "startPreview" -> {
+                startPreview()
+                result.success(true)
+            }
+            "stopPreview" -> {
+                stopPreview()
+                result.success(true)
+            }
+            "switchCamera" -> {
+                switchCamera()
+                result.success(true)
+            }
+            "setBeauty" -> {
+                setBeauty(call.argument<Int>("level")!!)
+                result.success(true)
+            }
+            "setFilter" -> {
+                setFilter(call.argument<String>("path")!!)
+                result.success(true)
+            }
+            "startRecord" -> {
+                startRecord(
+                        max = call.argument<Int>("max")!!, recordPath = call.argument<String>("recordPath")!!, result = result)
+            }
+            "startCompose" -> {
+                val outputPath = call.argument<String>("outputPath")!!
+                val bgmPath = call.argument<String>("bgmPath")
+                val paths = call.argument<List<String>>("paths")!!
+                val durations = call.argument<List<Int>>("durations")!!
+                val outputOption = call.argument<Map<String, Any>>("composeOption")!!
+                startCompose(outputPath = outputPath, bgmPath = bgmPath, paths = paths, durations = durations, outputOption = outputOption, result = result)
+            }
+            "onDestroy" -> {
+                onDestroy()
+                result.success(true)
+            }
+            else -> result.notImplemented()
         }
     }
 
-    fun setUpCameraView(context: Context, recordOption: Map<String, Any>) {
+    private fun setUpCameraView(recordOption: Map<String, Any>) {
         try {
             recorder = AliyunRecorderCreator.getRecorderInstance(context)
 
@@ -84,7 +150,7 @@ class AliCameraView(private val context: Context, private val channel: MethodCha
 
                 override fun onComplete(p0: Boolean, p1: Long) {
                     mainHandler.post {
-                        channel.invokeMethod("recordUpdate",
+                        methodChannel?.invokeMethod("recordUpdate",
                                 mapOf("progress" to recorder?.clipManager?.maxDuration, "path" to recorder?.clipManager?.videoPathList?.last()))
                     }
                 }
@@ -97,7 +163,7 @@ class AliCameraView(private val context: Context, private val channel: MethodCha
 
                 override fun onProgress(p0: Long) {
                     mainHandler.post {
-                        channel.invokeMethod("recordUpdate", mapOf("progress" to p0))
+                        methodChannel?.invokeMethod("recordUpdate", mapOf("progress" to p0))
                     }
                 }
 
@@ -110,24 +176,24 @@ class AliCameraView(private val context: Context, private val channel: MethodCha
         }
     }
 
-    fun startPreview() {
+    private fun startPreview() {
         recorder?.startPreview()
     }
 
-    fun stopPreview() {
+    private fun stopPreview() {
         recorder?.stopPreview()
     }
 
-    fun switchCamera() {
+    private fun switchCamera() {
         recorder?.switchCamera()
     }
 
-    fun setBeauty(level: Int) {
+    private fun setBeauty(level: Int) {
         recorder?.setBeautyStatus(level != 0)
         recorder?.beautyLevel = level
     }
 
-    fun setFilter(path: String) {
+    private fun setFilter(path: String) {
         if (path.isEmpty()) {
             recorder?.applyFilter(EffectFilter(null))
             return
@@ -135,7 +201,7 @@ class AliCameraView(private val context: Context, private val channel: MethodCha
         recorder?.applyFilter(EffectFilter(path))
     }
 
-    fun startRecord(max: Int, recordPath: String, result: MethodChannel.Result) {
+    private fun startRecord(max: Int, recordPath: String, result: MethodChannel.Result) {
         try {
             recorder?.setOutputPath(recordPath)
             //  补充时间段上去
@@ -148,7 +214,7 @@ class AliCameraView(private val context: Context, private val channel: MethodCha
         }
     }
 
-    fun startCompose(outputPath: String, bgmPath: String?, paths: List<String>, durations: List<Int>, outputOption: Map<String, Any>, result: MethodChannel.Result) {
+    private fun startCompose(outputPath: String, bgmPath: String?, paths: List<String>, durations: List<Int>, outputOption: Map<String, Any>, result: MethodChannel.Result) {
         try {
             // 配置输出参数
             val mImport = AliyunImportCreator.getImportInstance(context)
@@ -228,7 +294,7 @@ class AliCameraView(private val context: Context, private val channel: MethodCha
         }
     }
 
-    fun onDestroy() {
+    private fun onDestroy() {
         if (recorder != null) {
             recorder?.stopPreview()
             recorder?.stopRecording()
@@ -236,20 +302,4 @@ class AliCameraView(private val context: Context, private val channel: MethodCha
             recorder = null
         }
     }
-
-    override fun getView(): View {
-        setUpView(context)
-        return frameLayout!!
-    }
-
-    override fun dispose() {
-        if (frameLayout != null) {
-            frameLayout?.removeView(surfaceView)
-            frameLayout = null
-        }
-        if (surfaceView != null) {
-            surfaceView = null
-        }
-        onDestroy()
-    }
 }

+ 0 - 57
android/src/main/kotlin/com/i2edu/flutter_ali_camera/CameraMethodHandler.kt

@@ -1,72 +1,15 @@
 package com.i2edu.flutter_ali_camera
 
-import android.content.Context
-import com.aliyun.sys.AlivcSdkCore
 import io.flutter.plugin.common.*
-import io.flutter.plugin.platform.PlatformView
-import io.flutter.plugin.platform.PlatformViewFactory
 
 class CameraMethodHandler(
         private val flutterState: FlutterState) : MethodChannel.MethodCallHandler {
-    var camera: AliCameraView ?= null
 
     override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
         when (call.method) {
             "getPlatformVersion" -> {
                 result.success("Android ${android.os.Build.VERSION.RELEASE}")
             }
-            "initializeSdk" -> {
-                camera = AliCameraView(flutterState.context, flutterState.methodChannel)
-                flutterState.platformViewRegistry.registerViewFactory("com.i2edu.cameraLib", object : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
-                    override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
-                        return camera!!
-                    }
-                })
-                AlivcSdkCore.register(flutterState.context)
-                AlivcSdkCore.setLogLevel(AlivcSdkCore.AlivcLogLevel.AlivcLogDebug)
-                result.success(true)
-            }
-            "create" -> {
-                val recordOption: Map<String, Any> = call.argument<Map<String, Any>>("recordOption")!!
-                camera?.setUpCameraView(context = flutterState.context, recordOption = recordOption)
-                result.success(true)
-            }
-            "startPreview" -> {
-                camera?.startPreview()
-                result.success(true)
-            }
-            "stopPreview" -> {
-                camera?.stopPreview()
-                result.success(true)
-            }
-            "switchCamera" -> {
-                camera?.switchCamera()
-                result.success(true)
-            }
-            "setBeauty" -> {
-                camera?.setBeauty(call.argument<Int>("level")!!)
-                result.success(true)
-            }
-            "setFilter" -> {
-                camera?.setFilter(call.argument<String>("path")!!)
-                result.success(true)
-            }
-            "startRecord" -> {
-                camera?.startRecord(
-                        max = call.argument<Int>("max")!!, recordPath = call.argument<String>("recordPath")!!, result = result)
-            }
-            "startCompose" -> {
-                val outputPath = call.argument<String>("outputPath")!!
-                val bgmPath = call.argument<String>("bgmPath")
-                val paths = call.argument<List<String>>("paths")!!
-                val durations = call.argument<List<Int>>("durations")!!
-                val outputOption = call.argument<Map<String, Any>>("composeOption")!!
-                camera?.startCompose(outputPath = outputPath, bgmPath = bgmPath, paths = paths, durations = durations, outputOption = outputOption, result = result)
-            }
-            "onDestroy" -> {
-                camera?.onDestroy()
-                result.success(true)
-            }
             else -> {
                 result.notImplemented()
             }

+ 0 - 2
android/src/main/kotlin/com/i2edu/flutter_ali_camera/FlutterAliCameraPlugin.kt

@@ -1,10 +1,8 @@
 package com.i2edu.flutter_ali_camera
 
 import androidx.annotation.NonNull
-import io.flutter.app.FlutterActivity
 import io.flutter.embedding.engine.plugins.FlutterPlugin
 import io.flutter.plugin.common.PluginRegistry.Registrar
-import io.flutter.plugin.common.PluginRegistry
 
 /** FlutterAliCameraPlugin */
 public class FlutterAliCameraPlugin : FlutterPlugin {

+ 16 - 3
android/src/main/kotlin/com/i2edu/flutter_ali_camera/FlutterState.kt

@@ -1,18 +1,31 @@
 package com.i2edu.flutter_ali_camera
 
 import android.content.Context
+import com.aliyun.sys.AlivcSdkCore
 import io.flutter.plugin.common.MethodChannel
 import io.flutter.plugin.common.BinaryMessenger
+import io.flutter.plugin.common.StandardMessageCodec
+import io.flutter.plugin.platform.PlatformView
+import io.flutter.plugin.platform.PlatformViewFactory
 import io.flutter.plugin.platform.PlatformViewRegistry
 
 class FlutterState(
         val context: Context,
-        binaryMessenger: BinaryMessenger,
-        val platformViewRegistry: PlatformViewRegistry) {
+        val binaryMessenger: BinaryMessenger,
+        private val platformViewRegistry: PlatformViewRegistry) {
     
-    val methodChannel: MethodChannel = MethodChannel(binaryMessenger, "flutter_ali_camera")
+    private val methodChannel: MethodChannel = MethodChannel(binaryMessenger, "flutter_ali_camera")
 
     fun startListening(methodCallHandler: CameraMethodHandler) {
+        // resister alivcsdkcore
+        AlivcSdkCore.register(context)
+        AlivcSdkCore.setLogLevel(AlivcSdkCore.AlivcLogLevel.AlivcLogDebug)
+
+        platformViewRegistry.registerViewFactory("com.i2edu.cameraLib", object : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
+            override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
+                return AliCameraView(context, binaryMessenger, viewId, args)
+            }
+        })
         methodChannel.setMethodCallHandler(methodCallHandler)
     }
 

+ 100 - 77
example/lib/main.dart

@@ -2,13 +2,12 @@ import 'dart:io';
 import 'dart:async';
 
 import 'package:flutter/material.dart';
-import 'package:flutter_ali_camera/ali_camera.dart';
+import 'package:flutter_ali_camera/camera_export.dart';
 import 'package:path_provider/path_provider.dart';
 import 'package:path/path.dart' as path;
 
 void main() async {
   WidgetsFlutterBinding.ensureInitialized();
-  await FlutterAliCameraController.initializeSdk();
   runApp(FirstPage());
 }
 
@@ -34,9 +33,11 @@ class FirstState extends StatelessWidget {
     return Scaffold(
       body: Center(
         child: RawMaterialButton(
-          child: Text("push",),
+          child: Text(
+            "push",
+          ),
           onPressed: () {
-            Navigator.of(context).push(MaterialPageRoute(builder: (ctx){
+            Navigator.of(context).push(MaterialPageRoute(builder: (ctx) {
               return MyApp();
             }));
           },
@@ -44,7 +45,6 @@ class FirstState extends StatelessWidget {
       ),
     );
   }
-
 }
 
 class MyApp extends StatefulWidget {
@@ -53,7 +53,7 @@ class MyApp extends StatefulWidget {
 }
 
 class _MyAppState extends State<MyApp> {
-  FlutterAliCameraController _controller = FlutterAliCameraController();
+  final Completer<CameraViewController> _controller = Completer<CameraViewController>();
   StreamSubscription _durationSubscription; // 播放进度订阅
   final int duration = 5000;
   double value = 0;
@@ -68,19 +68,22 @@ class _MyAppState extends State<MyApp> {
   @override
   void dispose() {
     _durationSubscription.cancel();
-    _controller.dispose();
+    _dispose();
     super.dispose();
   }
 
-  void _onPlatformViewCreated() {
-    initPlatform();
+  void _dispose() async {
+    if (_controller.isCompleted) {
+      CameraViewController controller = await _controller.future;
+      controller.dispose();
+    }
   }
 
-  Future<void> initPlatform() async {
-    await _controller.create(
+  void _onPlatformViewCreated(CameraViewController controller) async {
+    await controller.create(
         recordOption: CameraRecordOption(
             videoWidth: 720, videoHeight: 1280, quality: VideoQuality.SD));
-    _durationSubscription = _controller.recordUpdate.listen((result) {
+    _durationSubscription = controller.recordUpdate.listen((result) {
       print("record update" + result.toString());
       if (result.containsKey("path")) {
         print("录制完成");
@@ -90,7 +93,6 @@ class _MyAppState extends State<MyApp> {
         });
       }
     });
-    setState(() {});
   }
 
   static Future<String> _findLocalPath() async {
@@ -100,18 +102,18 @@ class _MyAppState extends State<MyApp> {
     return directory.path;
   }
 
-  Future<void> _record() async {
+  Future<void> _record(CameraViewController controller) async {
     setState(() {
       recording = true;
     });
     String mp4Path = path.join(await _findLocalPath(), "1.mp4");
-    _controller.startRecord(duration, mp4Path);
+    controller.startRecord(duration, mp4Path);
   }
 
-  void _compose() async {
+  void _compose(CameraViewController controller) async {
     if (recordPath.length == 0) return;
     String resultPath = path.join(await _findLocalPath(), "result.mp4");
-    bool success = await _controller.startCompose(
+    bool success = await controller.startCompose(
       resultPath,
       null,
       recordPath,
@@ -140,71 +142,92 @@ class _MyAppState extends State<MyApp> {
           SizedBox(
             width: double.maxFinite,
             height: 200,
-            child: _controller.buildView(_onPlatformViewCreated),
+            child: CameraView(
+              onCameraViewCreated: (controller) {
+                _controller.complete(controller);
+                _onPlatformViewCreated(controller);
+              },
+            ),
           ),
-          Row(
-            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-            children: <Widget>[
-              IconButton(
-                  icon: Icon(
-                    Icons.play_arrow,
-                    size: 26,
-                  ),
-                  onPressed: () {
-                    if (!recording) _controller.startPreview();
-                  }),
-              IconButton(
-                  icon: Icon(
-                    Icons.pause,
-                    size: 26,
-                  ),
-                  onPressed: () {
-                    if (!recording) _controller.stopPreview();
-                  }),
-              IconButton(
-                  icon: Icon(
-                    Icons.switch_camera,
-                    size: 26,
-                  ),
-                  onPressed: () {
-                    if (!recording) _controller.switchCamera();
-                  }),
-              IconButton(
-                  icon: Icon(
-                    recording ? Icons.stop : Icons.fiber_manual_record,
-                    size: 26,
-                  ),
-                  onPressed: () {
-                    if (!recording) _record();
-                  }),
-              IconButton(
-                  icon: Icon(
-                    Icons.settings,
-                    size: 26,
-                  ),
-                  onPressed: () {
-                    if (!recording) _compose();
-                  }),
-            ],
+          FutureBuilder(
+            future: _controller.future,
+            builder: (ctx, controller) {
+              if (controller.hasData) {
+                return Row(
+                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+                  children: <Widget>[
+                    IconButton(
+                        icon: Icon(
+                          Icons.play_arrow,
+                          size: 26,
+                        ),
+                        onPressed: () {
+                          if (!recording) controller.data.startPreview();
+                        }),
+                    IconButton(
+                        icon: Icon(
+                          Icons.pause,
+                          size: 26,
+                        ),
+                        onPressed: () {
+                          if (!recording) controller.data.stopPreview();
+                        }),
+                    IconButton(
+                        icon: Icon(
+                          Icons.switch_camera,
+                          size: 26,
+                        ),
+                        onPressed: () {
+                          if (!recording) controller.data.switchCamera();
+                        }),
+                    IconButton(
+                        icon: Icon(
+                          recording ? Icons.stop : Icons.fiber_manual_record,
+                          size: 26,
+                        ),
+                        onPressed: () {
+                          if (!recording) _record(controller.data);
+                        }),
+                    IconButton(
+                        icon: Icon(
+                          Icons.settings,
+                          size: 26,
+                        ),
+                        onPressed: () {
+                          if (!recording) _compose(controller.data);
+                        }),
+                  ],
+                );
+              }
+              return Container();
+            },
           ),
           SizedBox(
             height: 5,
           ),
-          Row(
-            children: <Widget>[
-              Text("美颜0-100"),
-              Expanded(
-                child: Slider(
-                    value: value,
-                    max: 100,
-                    onChanged: (value) {
-                      _controller.setBeauty(value.toInt());
-                      setState(() {
-                        this.value = value;
-                      });
-                    }),
-              ),
-            ],
+          FutureBuilder(
+            future: _controller.future,
+            builder: (ctx, controller) {
+              if (controller.hasData) {
+                return Row(
+                  children: <Widget>[
+                    Text("美颜0-100"),
+                    Expanded(
+                      child: Slider(
+                          value: value,
+                          max: 100,
+                          onChanged: (value) {
+                            controller.data.setBeauty(value.toInt());
+                            setState(() {
+                              this.value = value;
+                            });
+                          }),
+                    ),
+                  ],
+                );
+              }
+              return Container();
+            },
           ),
         ],
       ),

+ 0 - 2
lib/ali_camera.dart

@@ -1,2 +0,0 @@
-export 'ali_camera_controller.dart';
-export 'camera_option.dart';

+ 0 - 99
lib/ali_camera_controller.dart

@@ -1,99 +0,0 @@
-import 'dart:async';
-import 'dart:convert';
-import 'dart:io';
-
-import 'package:flutter/material.dart';
-import 'package:flutter/services.dart';
-import 'package:flutter_ali_camera/camera_option.dart';
-
-class FlutterAliCameraController {
-
-  static const MethodChannel _channel =
-      const MethodChannel('flutter_ali_camera');
-  static const String viewType = "com.i2edu.cameraLib";
-  final StreamController<Map> _recordController = StreamController.broadcast();
-  Stream<Map> get recordUpdate => _recordController.stream;
-
-  static Future<String> get platformVersion async {
-    final String version = await _channel.invokeMethod('getPlatformVersion');
-    return version;
-  }
-
-  static Future<void> initializeSdk() {
-    return _channel.invokeMethod("initializeSdk");
-  }
-
-  Future<void> create({@required CameraRecordOption recordOption}) async {
-    _channel.setMethodCallHandler(_onMethodCallHandler);
-    return await _channel.invokeMethod("create", {"recordOption": recordOption.toMap()});
-  }
-
-  Widget buildView(VoidCallback onPlatformViewCreated) {
-    return Platform.isAndroid
-        ? AndroidView(
-            viewType: viewType,
-            creationParams: {},
-            creationParamsCodec: const StandardMessageCodec(),
-            onPlatformViewCreated: (id) => onPlatformViewCreated(),
-          )
-        : UiKitView(
-            viewType: viewType,
-            creationParams: {},
-            creationParamsCodec: const StandardMessageCodec(),
-            onPlatformViewCreated: (id) => onPlatformViewCreated(),
-          );
-  }
-
-  Future<void> startPreview() {
-    return _channel.invokeMethod("startPreview");
-  }
-
-  Future<void> stopPreview() {
-    return _channel.invokeMethod("stopPreview");
-  }
-
-  Future<void> switchCamera() {
-    return _channel.invokeMethod("switchCamera");
-  }
-
-  Future<void> setBeauty(int level) {
-    return _channel.invokeMethod("setBeauty", {"level": level});
-  }
-
-  Future<void> setFilter(String path) {
-    return _channel.invokeMethod("setFilter", {"path": path});
-  }
-
-  Future<void> startRecord(int max, String recordPath) {
-    return _channel.invokeMethod("startRecord", {"max": max, "recordPath": recordPath});
-  }
-
-  Future<bool> startCompose(String outputPath, String bgmPath,
-      List<String> paths, List<int> durations, CameraComposeOption option) {
-    if (paths.length != durations.length) {
-      print("error: length error");
-      return null;
-    }
-    return _channel.invokeMethod("startCompose", {
-      "outputPath": outputPath,
-      "bgmPath": bgmPath,
-      "paths": paths,
-      "durations": durations,
-      "composeOption": option.toMap()
-    });
-  }
-
-  Future _onMethodCallHandler(MethodCall call) {
-    print(call.arguments);
-    switch (call.method) {
-      case "recordUpdate":
-        _recordController.add(call.arguments);
-        break;
-    }
-    return null;
-  }
-
-  Future<void> dispose() async {
-    return _channel.invokeMethod("onDestroy");
-  }
-}

+ 4 - 0
lib/camera_export.dart

@@ -0,0 +1,4 @@
+export 'camera_plugin.dart';
+export 'camera_option.dart';
+export 'camera_view.dart';
+export 'camera_view_controller.dart';

+ 14 - 0
lib/camera_plugin.dart

@@ -0,0 +1,14 @@
+import 'dart:async';
+
+import 'package:flutter/services.dart';
+
+class FlutterAliCamera {
+
+  static const MethodChannel _channel =
+      const MethodChannel('flutter_ali_camera');
+
+  static Future<String> get platformVersion async {
+    final String version = await _channel.invokeMethod('getPlatformVersion');
+    return version;
+  }
+}

+ 45 - 0
lib/camera_view.dart

@@ -0,0 +1,45 @@
+import 'dart:async';
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_ali_camera/camera_export.dart';
+
+typedef OnCameraViewCreated(CameraViewController controller);
+
+class CameraView extends StatefulWidget {
+  final OnCameraViewCreated onCameraViewCreated;
+
+  const CameraView({Key key, this.onCameraViewCreated}) : super(key: key);
+
+  @override
+  _CameraViewState createState() => _CameraViewState();
+}
+
+class _CameraViewState extends State<CameraView> {
+  static const String viewType = "com.i2edu.cameraLib";
+
+  @override
+  Widget build(BuildContext context) {
+    return Platform.isAndroid
+        ? AndroidView(
+            viewType: viewType,
+            creationParams: {},
+            creationParamsCodec: const StandardMessageCodec(),
+            onPlatformViewCreated: onPlatformViewCreated,
+          )
+        : UiKitView(
+            viewType: viewType,
+            creationParams: {},
+            creationParamsCodec: const StandardMessageCodec(),
+            onPlatformViewCreated: onPlatformViewCreated,
+          );
+  }
+
+  void onPlatformViewCreated(int viewId) {
+    final CameraViewController controller = CameraViewController(id: viewId);
+    if (widget.onCameraViewCreated != null) {
+      widget.onCameraViewCreated(controller);
+    }
+  }
+}

+ 76 - 0
lib/camera_view_controller.dart

@@ -0,0 +1,76 @@
+import 'dart:async';
+
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/services.dart';
+
+import 'camera_option.dart';
+
+class CameraViewController {
+  MethodChannel _methodChannel;
+  final StreamController<Map> _recordController = StreamController.broadcast();
+
+  Stream<Map> get recordUpdate => _recordController.stream;
+
+  CameraViewController({@required int id}) {
+    _methodChannel = MethodChannel("com.i2edu.cameraLib/camera_view_$id");
+    _methodChannel.setMethodCallHandler(_onMethodCallHandler);
+  }
+
+  Future<void> create({@required CameraRecordOption recordOption}) async {
+    return _methodChannel.invokeMethod("create", {"recordOption": recordOption.toMap()});
+  }
+
+  Future<void> startPreview() {
+    return _methodChannel.invokeMethod("startPreview");
+  }
+
+  Future<void> stopPreview() {
+    return _methodChannel.invokeMethod("stopPreview");
+  }
+
+  Future<void> switchCamera() {
+    return _methodChannel.invokeMethod("switchCamera");
+  }
+
+  Future<void> setBeauty(int level) {
+    return _methodChannel.invokeMethod("setBeauty", {"level": level});
+  }
+
+  Future<void> setFilter(String path) {
+    return _methodChannel.invokeMethod("setFilter", {"path": path});
+  }
+
+  Future<void> startRecord(int max, String recordPath) {
+    return _methodChannel.invokeMethod("startRecord", {"max": max, "recordPath": recordPath});
+  }
+
+  Future<bool> startCompose(String outputPath, String bgmPath,
+      List<String> paths, List<int> durations, CameraComposeOption option) {
+    if (paths.length != durations.length) {
+      print("error: length error");
+      return null;
+    }
+    return _methodChannel.invokeMethod("startCompose", {
+      "outputPath": outputPath,
+      "bgmPath": bgmPath,
+      "paths": paths,
+      "durations": durations,
+      "composeOption": option.toMap()
+    });
+  }
+
+  void dispose() async {
+    if (!_recordController.isClosed) {
+      _recordController.close();
+    }
+  }
+
+  Future _onMethodCallHandler(MethodCall call) {
+    switch (call.method) {
+      case "recordUpdate":
+        _recordController.add(call.arguments);
+        break;
+    }
+    return null;
+  }
+}

+ 2 - 2
test/flutter_ali_camera_test.dart

@@ -1,6 +1,6 @@
 import 'package:flutter/services.dart';
 import 'package:flutter_test/flutter_test.dart';
-import 'package:flutter_ali_camera/ali_camera.dart';
+import 'package:flutter_ali_camera/camera_export.dart';
 
 void main() {
   const MethodChannel channel = MethodChannel('flutter_ali_camera');
@@ -18,6 +18,6 @@ void main() {
   });
 
   test('getPlatformVersion', () async {
-    expect(await FlutterAliCameraController.platformVersion, '42');
+    expect(await FlutterAliCamera.platformVersion, '42');
   });
 }