網(wǎng)頁設(shè)計(jì)的交流網(wǎng)站網(wǎng)站貼子推廣怎么做
鶴壁市浩天電氣有限公司
2026/01/24 10:42:08
網(wǎng)頁設(shè)計(jì)的交流網(wǎng)站,網(wǎng)站貼子推廣怎么做,域名沒過期 網(wǎng)站打不開怎么辦,個人網(wǎng)站免費(fèi)源碼Flutter在鴻蒙平臺實(shí)現(xiàn)相機(jī)預(yù)覽的技術(shù)實(shí)踐
大家好#xff0c;今天我們一起來看一下使用相機(jī)調(diào)用這個案例#xff0c;一起來看一下flutter代碼運(yùn)行到鴻蒙平臺的效果
首先大家需要下載這個倉庫
testcamera
1.下載代碼
git clone gitgitcode.com:openharmony-tpc/flutter_s…Flutter在鴻蒙平臺實(shí)現(xiàn)相機(jī)預(yù)覽的技術(shù)實(shí)踐大家好今天我們一起來看一下使用相機(jī)調(diào)用這個案例一起來看一下flutter代碼運(yùn)行到鴻蒙平臺的效果首先大家需要下載這個倉庫testcamera1.下載代碼git clone gitgitcode.com:openharmony-tpc/flutter_samples.git2.適配ohos的案例都在ohos目錄下AUTHORSadd_to_appdeeplink_store_examplegoogle_mapsplace_trackersimplistic_editor COMMITTERS.mdanalysis_defaultsdesktop_photo_searchinfinite_listplatform_channelstesting_app CONTRIBUTING.mdandroid_splash_screendocsios_app_clipplatform_component_demotool LICENSEanimationsexperimentalisolate_exampleplatform_designveggieseasons OAT.xmlasset_transformationflutter_maps_firestorejsonexampleplatform_view_swiftweb PATENTSbackground_isolate_channelsflutter_music_playermaterial_3_demoprovider_counterweb_embedding README.OpenSourcecode_sharingflutter_smart_agriculturenavigation_and_routingprovider_shopper README.en.mdcompass_appform_appnext_gen_ui_demosimple_shader README.mdcontext_menusgame_templateohossimplistic_calculator ?cd到ohos目錄下現(xiàn)在這里面就是我們的這些適配了ohos的目錄README.mdevent_bus_testhttp_testpath_parsing_testsqflite_test animation_demofloor_testjs_dart_demoperformancestring_scanner_test async_testflutter-pagload_native_resource_demopetitparser_testtest_uni_links asynchronousflutter_huawei_loginlocaltion_demopictures_provider_demotestcamera automated_testing_demoflutter_ohos_theme_fontsizescalelogging_testplatform_demotestchat cached_network_image_sampleflutter_page_sample1multi_productsplatform_testtestpicture channel_demoflutter_page_sample2node_test_serverplatformchannel_demotuple_test clock_testflutter_svg_testohos_flutter_photoviewpickerprovider_partrefreshuuid_test component_demoflutter_webview_demoohos_sqlite3_demorxdart_testvector_math_test dio_testgesture_intercept_demoohos_themeAdaptationscrollview_demovideo_full_screen docshttp_parser_testpath_drawing_testsqflite_helperxml_test我今天想學(xué)習(xí)的是testcamera3.進(jìn)入testcamera目錄cd testcamera4.現(xiàn)在就可以直接使用flutter run來測試了。這個時候會報錯 flutter_lints 2.0.3 (6.0.0 available) flutter_test 0.0.0 from sdk flutter leak_tracker 10.0.9 (11.0.2 available) leak_tracker_flutter_testing 3.0.9 (3.0.10 available) leak_tracker_testing 3.0.1 (3.0.2 available) lints 2.1.1 (6.0.0 available) matcher 0.12.17 (0.12.18 available) material_color_utilities 0.11.1 (0.13.0 available) meta 1.16.0 (1.17.0 available) path 1.9.1 sky_engine 0.0.0 from sdk flutter source_span 1.10.1 stack_trace 1.12.1 stream_channel 2.1.4 string_scanner 1.4.1 term_glyph 1.2.2 test_api 0.7.4 (0.7.8 available) vector_math 2.1.4 (2.2.0 available) vm_service 15.0.0 (15.0.2 available) Changed 27 dependencies! 12 packages have newer versions incompatible with dependency constraints. Try flutter pub outdated for more information. Launching lib/main.dart on 2LQ0224129000383 in debug mode... start hap build... Running Hvigor task assembleHap... 15.1s Error: 請通過DevEco Studio打開ohos工程后配置調(diào)試簽名(File - Project Structure - Signing Configs 勾選Automatically generate signature) ? ?所以需要大家在這里面ohos模塊簽名找到對應(yīng)的文件5.打開deveco。簽名6.現(xiàn)在就可以嘗試了flutter run Launching lib/main.dart on 2LQ0224129000383 in debug mode... start hap build... Running Hvigor task assembleHap... 10.7s ? Built ohos/entry/build/default/outputs/default/entry-default-signed.hap. installing hap. bundleName: com.example.testcamera 12-18 08:07:00.014 24792 24792 W A00000/com.example.testcamera/XComFlutterOHOS_Native: flutter settings log message: build textureId :-1 12-18 08:07:00.281 24792 24792 W A00000/com.example.testcamera/XComFlutterOHOS_Native: flutter settings log message: build textureId :1 waiting for a debug connection: http://127.0.0.1:55220/qL6lfbc1GRE/ Syncing files to device 2LQ0224129000383... 72ms ? Flutter run key commands. r Hot reload. ?已經(jīng)運(yùn)行成功。現(xiàn)在我們就可以對現(xiàn)在的源碼繼續(xù)分享了。一、項(xiàng)目概述本項(xiàng)目展示了如何在鴻蒙OpenHarmony平臺上使用Flutter框架實(shí)現(xiàn)相機(jī)預(yù)覽功能。這是一個典型的跨平臺開發(fā)場景通過Flutter的插件機(jī)制將鴻蒙原生的相機(jī)能力橋接到Flutter應(yīng)用中實(shí)現(xiàn)了高性能的相機(jī)預(yù)覽體驗(yàn)。技術(shù)棧Flutter框架用于UI層和業(yè)務(wù)邏輯ArkTS鴻蒙原生開發(fā)語言用于實(shí)現(xiàn)相機(jī)插件MethodChannelFlutter與原生平臺通信的橋梁TextureFlutter的紋理渲染機(jī)制用于顯示相機(jī)預(yù)覽流二、技術(shù)架構(gòu)2.1 整體架構(gòu)┌─────────────────────────────────────────┐ │ Flutter UI Layer │ │ (CameraPage.dart - Material Design) │ └──────────────┬──────────────────────────┘ │ MethodChannel │ (CameraControlChannel) ┌──────────────▼──────────────────────────┐ │ Flutter Plugin Bridge │ │ (CameraPlugin.ets - FlutterPlugin) │ └──────────────┬──────────────────────────┘ │ TextureRegistry │ (Surface ID) ┌──────────────▼──────────────────────────┐ │ HarmonyOS Camera API │ │ (ohos.multimedia.camera) │ └─────────────────────────────────────────┘2.2 數(shù)據(jù)流向Flutter端通過MethodChannel發(fā)送指令注冊紋理、啟動相機(jī)插件層接收指令調(diào)用鴻蒙相機(jī)API創(chuàng)建紋理Surface相機(jī)層將預(yù)覽流輸出到Surface渲染層通過Texture將Surface內(nèi)容渲染到Flutter Widget三、Flutter端實(shí)現(xiàn)3.1 主入口main.dartimport package:flutter/material.dart; ? import CameraPage.dart; ? void main() { runApp(const MyApp()); } ? class MyApp extends StatelessWidget { const MyApp({super.key}); ? // This widget is the root of your application. override Widget build(BuildContext context) { return MaterialApp( title: Flutter Demo, theme: ThemeData( // This is the theme of your application. // // Try running your application with flutter run. Youll see the // application has a blue toolbar. Then, without quitting the app, try // changing the primarySwatch below to Colors.green and then invoke // hot reload (press r in the console where you ran flutter run, // or simply save your changes to hot reload in a Flutter IDE). // Notice that the counter didnt reset back to zero; the application // is not restarted. primarySwatch: Colors.blue, ), home: const CameraPage(), ); } }主入口非常簡潔直接啟動CameraPage作為首頁。3.2 相機(jī)頁面CameraPage.dart這是Flutter端的核心實(shí)現(xiàn)展示了如何使用MethodChannel和Textureimport package:flutter/material.dart; import package:flutter/services.dart; import dart:math as math; ? class CameraPage extends StatefulWidget { const CameraPage({super.key}); override _CameraPageState createState() _CameraPageState(); } ? class _CameraPageState extends StateCameraPage { final MethodChannel _channel MethodChannel(CameraControlChannel); ? int textureId -1; ? override void initState() { super.initState(); ? newTexture(); startCamera(); } ? override void dispose() { super.dispose(); if (textureId 0) { _channel.invokeMethod(unregisterTexture, {textureId: textureId}); } } ? void startCamera() async { await _channel.invokeMethod(startCamera); } ? void newTexture() async { int id await _channel.invokeMethod(registerTexture); setState(() { this.textureId id; }); } ? Widget getTextureBody(BuildContext context) { return Container( width: 500, height: 500, child: Texture( textureId: textureId, ), ); } ? override Widget build(BuildContext context) { Widget body textureId 0 ? getTextureBody(context) : Text(loading...); print(build textureId :$textureId); ? return Scaffold( appBar: AppBar( title: Text(daex_texture), ), body: Container( color: Colors.white, height: 500, child: Center( child: body, ), ), ); } }關(guān)鍵技術(shù)點(diǎn)MethodChannel通信通道名稱CameraControlChannel必須與原生端保持一致三個核心方法registerTexture注冊紋理獲取textureIdstartCamera啟動相機(jī)預(yù)覽unregisterTexture釋放紋理資源Texture WidgetFlutter提供的原生紋理渲染組件通過textureId與原生平臺的Surface綁定實(shí)現(xiàn)零拷貝的高性能渲染生命周期管理initState初始化時注冊紋理并啟動相機(jī)dispose頁面銷毀時釋放紋理資源防止內(nèi)存泄漏四、鴻蒙端實(shí)現(xiàn)ArkTS4.1 插件注冊EntryAbility.etsimport { FlutterAbility } from ohos/flutter_ohos import { GeneratedPluginRegistrant } from ../plugins/GeneratedPluginRegistrant; import FlutterEngine from ohos/flutter_ohos/src/main/ets/embedding/engine/FlutterEngine; import { CameraPlugin } from ../cameraplugin/CameraPlugin; ? export default class EntryAbility extends FlutterAbility { configureFlutterEngine(flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) GeneratedPluginRegistrant.registerWith(flutterEngine) this.addPlugin(new CameraPlugin()); } }插件在Flutter引擎初始化時注冊確保在應(yīng)用啟動時即可使用。4.2 相機(jī)插件CameraPlugin.ets這是整個插件的核心實(shí)現(xiàn)了FlutterPlugin和MethodCallHandler接口export class CameraPlugin implements FlutterPlugin, MethodCallHandler { private binding: FlutterPluginBinding | null null; private mMethodChannel: MethodChannel | null null; private textureRegistry: TextureRegistry | null null; private textureId: number -1; private surfaceId: number -1; ? getUniqueClassName(): string { return TAG; } ? onAttachedToEngine(binding: FlutterPluginBinding): void { Log.e(TAG, CameraPlugin onAttachedToEngine); this.binding binding; this.mMethodChannel new MethodChannel(binding.getBinaryMessenger(), CameraControlChannel); this.mMethodChannel.setMethodCallHandler(this); this.textureRegistry binding.getTextureRegistry(); ? } ? onDetachedFromEngine(binding: FlutterPluginBinding): void { this.binding null; this.mMethodChannel null; } ? onMethodCall(call: MethodCall, result: MethodResult): void { let method: string call.method; Log.e(TAG, Received method message.); switch (method) { case registerTexture: this.registerCameraTexture(); result.success(this.textureId); break; case startCamera: this.startCamera(); result.success(null); break; case unregisterTexture: this.unregisterTexture(call.argument(textureId)); result.success(null); break; } } ? getTextureId(): number { return this.textureId } ? registerCameraTexture(): void { Log.i(TAG, start register Camera texture in flutter engine); this.textureId this.textureRegistry!.getTextureId(); this.surfaceId this.textureRegistry!.registerTexture(this.textureId)!.getSurfaceId(); } ? unregisterTexture(textureId: number): void { this.textureRegistry!.unregisterTexture(textureId); } ? startCamera() { checkPermissions(permissions).then((value: boolean) { if (value) { this.startSession(); } else { // 獲取權(quán)限 reqPermissionsFromUser(permissions, getContext(this) as Context).then((value: boolean) { if (value) { this.startSession(); } else { console.log([camera test] 授權(quán)失敗); } }); } }); } ? startSession() { console.log([camera test] 已經(jīng)授權(quán)相機(jī)開始拍攝); let cameraManager getCameraManager(getContext(this) as common.BaseContext); let cameraDevices getCameraDevices(cameraManager); let cameraInput getCameraInput(cameraDevices[0], cameraManager); if (cameraInput ! null) { getSupportedOutputCapability(cameraDevices[0], cameraManager, cameraInput) .then((supportedOutputCapability) { if (supportedOutputCapability ! undefined) { let previewOutput getPreviewOutput(cameraManager, supportedOutputCapability, this.surfaceId.toString()); let captureSession getCaptureSession(cameraManager); if (captureSession ! undefined previewOutput ! undefined cameraInput ! null) { beginConfig(captureSession); setSessionCameraInput(captureSession, cameraInput); setSessionPreviewOutput(captureSession, previewOutput); startSession(captureSession); } } }); } } }核心流程插件生命周期onAttachedToEngine創(chuàng)建MethodChannel獲取TextureRegistryonDetachedFromEngine清理資源紋理注冊從TextureRegistry獲取唯一的textureId注冊紋理并獲取對應(yīng)的Surface IDSurface ID將用于相機(jī)預(yù)覽輸出相機(jī)啟動流程權(quán)限檢查 → 獲取相機(jī)管理器 → 創(chuàng)建輸入流 → 獲取輸出能力 → 創(chuàng)建預(yù)覽輸出 → 配置會話 → 啟動會話4.3 相機(jī)工具類CameraUtil.ets封裝了鴻蒙相機(jī)API的調(diào)用邏輯export function getCameraManager(context: common.BaseContext): camera.CameraManager { let cameraManager: camera.CameraManager camera.getCameraManager(context); return cameraManager; } ? /** * 通過cameraManager類中的getSupportedCameras()方法獲取當(dāng)前設(shè)備支持的相機(jī)列表列表中存儲了設(shè)備支持的所有相機(jī)ID。 * 若列表不為空則說明列表中的每個ID都支持獨(dú)立創(chuàng)建相機(jī)對象否則說明當(dāng)前設(shè)備無可用相機(jī)不可繼續(xù)后續(xù)操作。 * param cameraManager * returns */ export function getCameraDevices(cameraManager: camera.CameraManager): Arraycamera.CameraDevice { let cameraArray: Arraycamera.CameraDevice cameraManager.getSupportedCameras(); if (cameraArray ! undefined cameraArray.length 0) { console.error([camera test] cameraManager.getSupportedCameras error); return []; } for (let index 0; index cameraArray.length; index) { console.info([camera test] cameraId : cameraArray[index].cameraId); // 獲取相機(jī)ID console.info([camera test] cameraPosition : cameraArray[index].cameraPosition); // 獲取相機(jī)位置 console.info([camera test] cameraType : cameraArray[index].cameraType); // 獲取相機(jī)類型 console.info([camera test] connectionType : cameraArray[index].connectionType); // 獲取相機(jī)連接類型 } return cameraArray; } ? /** * 調(diào)用cameraManager類中的createCaptureSession()方法創(chuàng)建一個會話 * param cameraManager * returns */ export function getCaptureSession(cameraManager: camera.CameraManager): camera.CaptureSession | undefined { let captureSession: camera.CaptureSession | undefined undefined; try { captureSession cameraManager.createCaptureSession(); } catch (error) { let err error as BusinessError; console.error([camera test] Failed to create the CaptureSession instance. error: ${JSON.stringify(err)}); } return captureSession; } ? /** * 調(diào)用captureSession類中的beginConfig()方法配置會話 * param captureSession */ export function beginConfig(captureSession: camera.CaptureSession): void { try { captureSession.beginConfig(); } catch (error) { let err error as BusinessError; console.error([camera test] Failed to beginConfig. error: ${JSON.stringify(err)}); } } ? /** * 調(diào)用captureSession類中的commitConfig()和start()方法提交相關(guān)配置并啟動會話 * param captureSession * returns */ export async function startSession(captureSession: camera.CaptureSession): Promisevoid { try { await captureSession.commitConfig(); } catch (error) { let err error as BusinessError; console.error([camera test] Failed to commitConfig. error: ${JSON.stringify(err)}); } ? try { await captureSession.start() } catch (error) { let err error as BusinessError; console.error([camera test] Failed to start. error: ${JSON.stringify(err)}); } } ? export function getCameraInput(cameraDevice: camera.CameraDevice, cameraManager: camera.CameraManager): camera.CameraInput | null{ // 創(chuàng)建相機(jī)輸入流 let cameraInput: camera.CameraInput | null null; try { cameraInput cameraManager.createCameraInput(cameraDevice); // 監(jiān)聽cameraInput錯誤信息 cameraInput.on(error, cameraDevice, (error: BusinessError) { console.info([camera test] Camera input error code: ${error.code}); }); } catch (error) { let err error as BusinessError; console.error([camera test] Failed to createCameraInput errorCode err.code); } ? return cameraInput; } ? /** * 通過getSupportedOutputCapability()方法獲取當(dāng)前設(shè)備支持的所有輸出流 * 輸出流在CameraOutputCapability中的各個profile字段中 * param cameraDevice * param cameraManager * returns */ export async function getSupportedOutputCapability(cameraDevice: camera.CameraDevice, cameraManager: camera.CameraManager, cameraInput: camera.CameraInput): Promisecamera.CameraOutputCapability | undefined { // 打開相機(jī) await cameraInput.open(); // 獲取相機(jī)設(shè)備支持的輸出流能力 let cameraOutputCapability cameraManager.getSupportedOutputCapability(cameraDevice); if (!cameraOutputCapability) { console.error([camera test] cameraManager.getSupportedOutputCapability error); return undefined; } console.info([camera test] outputCapability: JSON.stringify(cameraOutputCapability)); return cameraOutputCapability; } ? /** * 獲取預(yù)覽流 * param cameraManager * param cameraOutputCapability * param surfaceId * returns */ export function getPreviewOutput(cameraManager: camera.CameraManager, cameraOutputCapability: camera.CameraOutputCapability, surfaceId: string): camera.PreviewOutput | undefined { let previewProfilesArray: Arraycamera.Profile cameraOutputCapability.previewProfiles; let previewOutput: camera.PreviewOutput | undefined undefined; try { previewOutput cameraManager.createPreviewOutput(previewProfilesArray[0], surfaceId); } catch (error) { let err error as BusinessError; console.error([camera test] Failed to create the PreviewOutput instance. error code: err.code); } return previewOutput; } ? export function setSessionCameraInput(captureSession: camera.CaptureSession, cameraInput: camera.CameraInput): void{ try { captureSession.addInput(cameraInput); } catch (error) { let err error as BusinessError; console.error([camera test] Failed to addInput. error: ${JSON.stringify(err)}); } } ? export function setSessionPreviewOutput(captureSession: camera.CaptureSession, previewOutput: camera.PreviewOutput): void{ try { captureSession.addOutput(previewOutput); } catch (error) { let err error as BusinessError; console.error([camera test] Failed to add previewOutput. error: ${JSON.stringify(err)}); } }關(guān)鍵函數(shù)說明getCameraManager獲取相機(jī)管理器實(shí)例getCameraDevices枚舉設(shè)備支持的相機(jī)前置/后置getCameraInput創(chuàng)建相機(jī)輸入流并監(jiān)聽錯誤事件getSupportedOutputCapability獲取相機(jī)支持的輸出能力需要先打開相機(jī)getPreviewOutput創(chuàng)建預(yù)覽輸出關(guān)鍵是將Surface ID傳入會話管理beginConfig → addInput/addOutput → commitConfig → start歡迎大家加入開源鴻蒙跨平臺開發(fā)者社區(qū)匯聚全球開發(fā)者提供清晰的貢獻(xiàn)路徑與激勵體系你的每一行代碼都可能成為產(chǎn)業(yè)升級的基石