成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

小白也能開發相機?Sample來教你

開發 前端
相機是智能設備最重要的功能之一,它能捕捉美好的瞬間、記錄關鍵的時刻,被廣泛應用于日常生活中。本文將詳細地講解一個帶有拍攝照片和錄制視頻功能的相機開發過程。

[[418309]]

想了解更多內容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術社區

https://harmonyos.51cto.com

上期我們給大家介紹了HarmonyOS Sample,收到了不少小伙伴的反饋,想學習一下HarmonyOS相機開發,現在,他來了!

相機開發概覽

相機是智能設備最重要的功能之一,它能捕捉美好的瞬間、記錄關鍵的時刻,被廣泛應用于日常生活中。本文將詳細地講解一個帶有拍攝照片和錄制視頻功能的相機開發過程。

小白也能開發相機?Sample來教你-鴻蒙HarmonyOS技術社區

目前,HarmonyOS相機模塊支持相機業務的開發,開發者可以通過已開放的接口實現相機硬件的訪問、操作和新功能開發。如下圖所示,是HarmonyOS為相機應用開發者提供的3個包的內容,包括方法、枚舉、以及常量/變量,方便開發者更容易地實現相機功能:

小白也能開發相機?Sample來教你-鴻蒙HarmonyOS技術社區

相機的開發流程如圖所示:

小白也能開發相機?Sample來教你-鴻蒙HarmonyOS技術社區

相機權限申請

在使用相機之前,需要申請相機的相關權限,比如獲取設備的相機權限、麥克風權限、存儲權限等。保證應用擁有相機硬件及其他功能權限。

視頻鏈接

開發者需在config.json中配置相關的權限,如下所示:

  1. "reqPermissions": [ 
  2.   { 
  3.     "name""ohos.permission.CAMERA" 
  4.   }, 
  5.   { 
  6.     "name""ohos.permission.WRITE_USER_STORAGE" 
  7.   }, 
  8.   { 
  9.     "name""ohos.permission.READ_USER_STORAGE" 
  10.   }, 
  11.   { 
  12.     "name""ohos.permission.MICROPHONE" 
  13.   }, 
  14.   { 
  15.     "name""ohos.permission.LOCATION" 
  16.   } 

獲取相關權限的具體代碼如下所示:

  1. private void requestPermissions() { 
  2.     String[] permissions = { 
  3.             //允許應用程序創建或刪除文件,或將數據寫入設備存儲中的文件。 
  4.             SystemPermission.WRITE_USER_STORAGE, 
  5.             //允許應用程序從設備存儲中讀取文件。 
  6.             SystemPermission.READ_USER_STORAGE, 
  7.             //允許應用程序使用相機。 
  8.             SystemPermission.CAMERA, 
  9.             //允許應用程序訪問麥克風。 
  10.             SystemPermission.MICROPHONE, 
  11.             //允許應用程序獲取設備位置。 
  12.             SystemPermission.LOCATION 
  13.     }; 
  14.     List<String> permissionFiltered = Arrays.stream(permissions) 
  15.         .filter(permission -> verifySelfPermission(permission) != IBundleManager.PERMISSION_GRANTED) 
  16.         .collect(Collectors.toList()); 
  17.     requestPermissionsFromUser(permissionFiltered.toArray(new String[permissionFiltered.size()]), 0); 

初始化相機界面

獲取到設備權限后,需要初始化相機界面。通過getWindow()獲取當前Ability對應的窗口,再通過addCallback()添加界面操作的回調。代碼如下所示:

  1. private void initSurface() { 
  2.     //獲取當前Ability對應的窗口,設置是否啟用透明度。isEnable -指定是否啟用透明度。True表示啟用透明度,False表示禁用。 
  3.     getWindow().setTransparent(true); 
  4.     DirectionalLayout.LayoutConfig params = new DirectionalLayout.LayoutConfig( 
  5.         ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT); 
  6.     surfaceProvider = new SurfaceProvider(this); 
  7.     surfaceProvider.setLayoutConfig(params); 
  8.     /** 
  9.      * 設置是否將此SurfaceProvider的Surface放置在AGP容器組件的頂層。 
  10.      * 參數說明: 
  11.      * toTop -指定是否將相機界面固定在頂部。值true表示將Surface放在AGP容器組件的頂層,而值false表示相反。*/ 
  12.     surfaceProvider.pinToZTop(false); 
  13.     //通過addCallback()添加界面操作的回調 
  14.     surfaceProvider.getSurfaceOps().get().addCallback(new SurfaceCallBack()); 
  15.     surfaceContainer.addComponent(surfaceProvider); 

通過postTask()來執行相機任務:

  1. private class SurfaceCallBack implements SurfaceOps.Callback { 
  2.     @Override 
  3.     public void surfaceCreated(SurfaceOps callbackSurfaceOps) { 
  4.         if (callbackSurfaceOps != null) { 
  5.             //setFixedSize:設置界面的固定大小。參數說明:寬度-指示界面的寬度。高度-指示界面的高度。 
  6.             callbackSurfaceOps.setFixedSize(SCREEN_HEIGHT,SCREEN_WIDTH); 
  7.         } 
  8. //設置延時200ms的postTask,用于相機界面的顯示 
  9.         eventHandler.postTask(new Runnable() { 
  10.             @Override 
  11.             public void run() { 
  12.                 openCamera(); 
  13.             } 
  14.         },200); 
  15.     } 

相機設備創建

1.創建相機對象

相機界面準備好后,我們需要創建相機設備。在實現一個相機應用之前必須先創建一個獨立的相機設備,然后才能繼續相機的其他操作。CameraKit類是相機的入口API類,如下所示:

小白也能開發相機?Sample來教你-鴻蒙HarmonyOS技術社區

相機設備創建的代碼如下:

  1. private void openCamera() { 
  2.     //ImageReceiver:連接到圖像輸出設備的圖像接收器,并提供一個緩沖隊列來接收圖像數據 
  3.     //create:根據指定的圖像寬度、高度、格式和緩沖隊列容量創建ImageReceiver實例 
  4.     imageReceiver = ImageReceiver.create(SCREEN_WIDTH, SCREEN_HEIGHT, ImageFormat.JPEG, IMAGE_RCV_CAPACITY); 
  5.     //設置接收到新圖像數據時將調用的圖像偵聽器。 
  6.     imageReceiver.setImageArrivalListener(this::saveImage); 
  7.     //獲取CameraKit實例 
  8.     CameraKit cameraKit = CameraKit.getInstance(getApplicationContext()); 
  9.     //獲取當前使用的設備支持的邏輯相機列表 
  10.     String[] cameraList = cameraKit.getCameraIds(); 
  11.     String cameraId = ""
  12.     //獲取當前邏輯相機的信息 
  13.     for (String logicalCameraId : cameraList) { 
  14.         int faceType = cameraKit.getCameraInfo(logicalCameraId).getFacingType(); 
  15.         switch (faceType){ 
  16.             case CameraInfo.FacingType.CAMERA_FACING_FRONT: 
  17.                 if (isFrontCamera) { 
  18.                     cameraId = logicalCameraId; 
  19.                 } 
  20.                 break; 
  21.             case CameraInfo.FacingType.CAMERA_FACING_BACK: 
  22.                 if (!isFrontCamera) { 
  23.                     cameraId = logicalCameraId; 
  24.                 } 
  25.                 break; 
  26.             case CameraInfo.FacingType.CAMERA_FACING_OTHERS: 
  27.             default
  28.                 break; 
  29.         } 
  30.     } 
  31.     if (cameraId != null && !cameraId.isEmpty()) { 
  32.         CameraStateCallbackImpl cameraStateCallback = new CameraStateCallbackImpl(); 
  33.         /**createCamera()用于創建相機對象 
  34.          * 該方法的第一個參數代表要打開的攝像頭ID; 
  35.          * 第二個參數用于監聽攝像頭的狀態; 
  36.          * 第三個參數代表執行callback的Handler,如果程序希望直接在當前線程中執行callback,則可將handler參數設為null。*/ 
  37.         cameraKit.createCamera(cameraId, cameraStateCallback, eventHandler); 
  38.     } 

創建相機設備成功后,在CameraStateCallback中會觸發onCreated(Camera camera)回調,并且帶回Camera對象,用于執行相機設備的操作。

  1. @Override 
  2. public void onCreated(Camera camera) { 
  3.     previewSurface = surfaceProvider.getSurfaceOps().get().getSurface(); 
  4.     if (previewSurface == null) { 
  5.         HiLog.error(LABEL_LOG, "%{public}s""Create camera filed, preview surface is null"); 
  6.         return
  7.     } 
  8.     //獲取相機Config.Builder實例。 
  9.     CameraConfig.Builder cameraConfigBuilder = camera.getCameraConfigBuilder(); 
  10.     //addSurface:添加界面作為相機流的輸出。 
  11.     cameraConfigBuilder.addSurface(previewSurface); 
  12.     cameraConfigBuilder.addSurface(imageReceiver.getRecevingSurface()); 
  13.     camera.configure(cameraConfigBuilder.build()); 
  14.     cameraDevice = camera; 
  15.     updateComponentVisible(true); 

2.配置預覽

在使用相機的過程中,用戶一般都是先看見預覽畫面才執行拍照或者其他功能,所以對于一個普通的相機應用,預覽是必不可少的。在上述CameraStateCallback中,會調用configure()方法實現預覽配置,通過triggerLoopingCapture()方法實現循環幀捕獲,從而達到預覽的目的。具體代碼如下:

  1. @Override 
  2. public void onConfigured(Camera camera) { 
  3.     FrameConfig.Builder framePreviewConfigBuilder = camera.getFrameConfigBuilder(FRAME_CONFIG_PREVIEW); 
  4.     framePreviewConfigBuilder.addSurface(previewSurface); 
  5.     //triggerLoopingCapture:開始循環幀捕獲。循環幀捕獲通常用于預覽或錄制 
  6.     camera.triggerLoopingCapture(framePreviewConfigBuilder.build()); 

相機功能實現

相機的基本功能主要分為拍攝照片和錄制視頻,目前HarmonyOS為開發者提供了如下相機拍照功能實現的Camera操作類,開發者可以通過這些方法,實現各種相機應用的開發:

小白也能開發相機?Sample來教你-鴻蒙HarmonyOS技術社區

如下圖所示是相機的使用過程,接下來的相機功能實現,也會根據此流程圖來實現。

小白也能開發相機?Sample來教你-鴻蒙HarmonyOS技術社區

(1)選擇功能

通過初始化相機界面組件,設置點擊事件偵聽器來實現相機功能選擇。代碼如下所示:

  1. private void initComponents() { 
  2.     Component takePhoto = findComponentById(ResourceTable.Id_take_photo); 
  3.     Component videoRecord = findComponentById(ResourceTable.Id_video_record); 
  4.     //設置點擊事件偵聽器,用于拍攝照片 
  5.     takePhoto.setClickedListener((component) -> startAbility(TakePhotoAbility.class.getName())); 
  6.     //設置點擊事件偵聽器,用于錄制視頻 
  7.     videoRecord.setClickedListener((component) -> startAbility(VideoRecordAbility.class.getName())); 

(2)切換攝像頭

開始拍攝照片或錄制視頻時,由于相機默認打開后置攝像頭,需根據場景切換前置攝像頭或后置攝像頭。如果檢測到相機正在工作中,將執行release()方法釋放當前相機設備。代碼如下:

  1. Image takePhotoImage = (Image) findComponentById(ResourceTable.Id_tack_picture_btn); 
  2. //setClickedListener:為組件中的單擊事件注冊偵聽器。 
  3. takePhotoImage.setClickedListener(this::takeSingleCapture); 
  4.  
  5. private void takeSingleCapture(Component component) { 
  6.     if (cameraDevice == null || imageReceiver == null) { 
  7.         return
  8.     } 
  9.     //用于配置幀捕獲、圖像處理和圖像輸出的接口 
  10.     FrameConfig.Builder framePictureConfigBuilder = cameraDevice.getFrameConfigBuilder(FRAME_CONFIG_PICTURE); 
  11.     framePictureConfigBuilder.addSurface(imageReceiver.getRecevingSurface()); 
  12.     FrameConfig pictureFrameConfig = framePictureConfigBuilder.build(); 
  13.     //triggerSingleCapture():開始單幀捕獲。這種方法通常用于拍照。 
  14.     cameraDevice.triggerSingleCapture(pictureFrameConfig); 

(3)拍攝照片

拍照功能屬于相機應用的最重要功能之一,而且照片質量對用戶至關重要。相機模塊基于相機復雜的邏輯,從應用接口層到器件驅動層都已經默認的做好了最適合用戶的配置,這些默認配置盡可能地保證用戶拍出的每張照片的質量。

實現單幀拍照

單幀拍照,其實就是單幀捕獲的過程。通過設置點擊事件偵聽器setClickedListener(),來觸發takeSingleCapture()方法,實現單幀捕獲。具體代碼如下:

  1. Image takePhotoImage = (Image) findComponentById(ResourceTable.Id_tack_picture_btn); 
  2. //setClickedListener:為組件中的單擊事件注冊偵聽器。 
  3. takePhotoImage.setClickedListener(this::takeSingleCapture); 
  4.  
  5. private void takeSingleCapture(Component component) { 
  6.     if (cameraDevice == null || imageReceiver == null) { 
  7.         return
  8.     } 
  9.     //用于配置幀捕獲、圖像處理和圖像輸出的接口 
  10.     FrameConfig.Builder framePictureConfigBuilder = cameraDevice.getFrameConfigBuilder(FRAME_CONFIG_PICTURE); 
  11.     framePictureConfigBuilder.addSurface(imageReceiver.getRecevingSurface()); 
  12.     FrameConfig pictureFrameConfig = framePictureConfigBuilder.build(); 
  13.     //triggerSingleCapture():開始單幀捕獲。這種方法通常用于拍照。 
  14.     cameraDevice.triggerSingleCapture(pictureFrameConfig); 

實現連拍

連拍功能方便用戶一次拍照獲取多張照片,用于捕捉精彩瞬間。

同單幀拍照的實現流程一致,但連拍需要使用triggerMultiCapture(frameConfigs)方法用于多幀捕獲。

  1. private void takeMultiCapture(Component component) { 
  2.     FrameConfig.Builder framePictureConfigBuilder = cameraDevice.getFrameConfigBuilder(FRAME_CONFIG_PICTURE); 
  3.     framePictureConfigBuilder.addSurface(imageReceiver.getRecevingSurface()); 
  4.     List<FrameConfig> frameConfigs = new ArrayList<>(); 
  5.     FrameConfig firstFrameConfig = framePictureConfigBuilder.build(); 
  6.     frameConfigs.add(firstFrameConfig); 
  7.     FrameConfig secondFrameConfig = framePictureConfigBuilder.build(); 
  8.     frameConfigs.add(secondFrameConfig); 
  9.     /**triggerMultiCapture(frameConfigs):啟動多幀捕獲。 
  10.     cameraDevice.triggerMultiCapture(frameConfigs); 

存儲照片

拍攝后的照片通過saveImage()實現照片存儲。具體代碼如下:

  1. /** 
  2.   * 存儲照片*/ 
  3. private void saveImage(ImageReceiver receiver) { 
  4.     //getFilesDir():獲取應用程序在設備內部存儲上的文件存儲目錄。 
  5.     File saveFile = new File(getFilesDir(), "IMG_" + System.currentTimeMillis() + ".jpg"); 
  6.     ohos.media.image.Image image = receiver.readNextImage(); 
  7.     //定義圖像格式,提供獲取圖像格式信息的接口。 
  8.     ohos.media.image.Image.Component component = image.getComponent(ImageFormat.ComponentType.JPEG); 
  9.     byte[] bytes = new byte[component.remaining()]; 
  10.     component.read(bytes); 
  11.     try (FileOutputStream output = new FileOutputStream(saveFile)) { 
  12.         output.write(bytes); 
  13.         output.flush(); 
  14.         showTips(this, "Take photo succeed"); 
  15.     } catch (IOException e) { 
  16.         HiLog.error(LABEL_LOG, "%{public}s""saveImage IOException"); 
  17.     } 

(4)錄制視頻

配置音視頻模塊

錄制視頻除了要進行預覽配置,還需要進行音視頻模塊的配置。

比如視頻編碼格式配置:

  1. setRecorderVideoEncoder(Recorder.VideoEncoder.H264) 

音頻編碼格式配置:

  1. setRecorderAudioEncoder(Recorder.AudioEncoder.AAC) 

以及視頻的編碼碼率、幀捕獲率、幀率配置等。代碼如下所示:

  1. private void initMediaRecorder() { 
  2.     mediaRecorder = new Recorder(); 
  3.     VideoProperty.Builder videoPropertyBuilder = new VideoProperty.Builder(); 
  4.     videoPropertyBuilder.setRecorderBitRate(10000000);//setRecorderBitRate:設置視頻編碼碼率。 
  5.     videoPropertyBuilder.setRecorderDegrees(90);  //setRecorderDegrees:設置視頻旋轉角度。 
  6.     videoPropertyBuilder.setRecorderFps(30);//setRecorderFps:設置視頻幀捕獲速率。 
  7.     videoPropertyBuilder.setRecorderHeight(Math.min(1440, 720));//設置視頻高度。 
  8.     videoPropertyBuilder.setRecorderWidth(Math.max(1440, 720));//設置視頻寬度。 
  9.     videoPropertyBuilder.setRecorderVideoEncoder(Recorder.VideoEncoder.H264);//setRecorderVideoEncoder:設置視頻編碼格式。 
  10.     videoPropertyBuilder.setRecorderRate(30);//setRecorderRate:設置視頻幀率。 
  11.  
  12.     Source source = new Source(); 
  13.     //表示使用麥克風作為音頻源。 
  14.     source.setRecorderAudioSource(Recorder.AudioSource.MIC); 
  15.     //表示使用相機界面作為視頻源。 
  16.     source.setRecorderVideoSource(Recorder.VideoSource.SURFACE); 
  17.     mediaRecorder.setSource(source); 
  18.     //setOutputFormat:設置輸出文件格式。 
  19.     mediaRecorder.setOutputFormat(Recorder.OutputFormat.MPEG_4); 
  20.     //getFilesDir():獲取文件存儲目錄。 
  21.     File file = new File(getFilesDir(), "VID_" + System.currentTimeMillis() + ".mp4"); 
  22.     StorageProperty.Builder storagePropertyBuilder = new StorageProperty.Builder(); 
  23.     storagePropertyBuilder.setRecorderFile(file); 
  24.     mediaRecorder.setStorageProperty(storagePropertyBuilder.build()); 
  25.  
  26.     AudioProperty.Builder audioPropertyBuilder = new AudioProperty.Builder(); 
  27.     //setRecorderAudioEncoder:設置音頻編碼格式。 
  28.     audioPropertyBuilder.setRecorderAudioEncoder(Recorder.AudioEncoder.AAC); 
  29.     mediaRecorder.setAudioProperty(audioPropertyBuilder.build()); 
  30.     mediaRecorder.setVideoProperty(videoPropertyBuilder.build()); 
  31.     mediaRecorder.prepare(); 

開始錄制

通過設置長按點擊事件偵聽器setLongClickedListener()來觸發startRecord(),實現開始錄制。代碼如下:

  1. //為組件中的長單擊事件注冊偵聽器(單擊并按住組件)。所有注冊的觀察員都將收到調度到組件的長單擊事件的通知。 
  2. videoRecord.setLongClickedListener(component -> { 
  3.     startRecord(); 
  4.     isRecording = true
  5.     videoRecord.setPixelMap(ResourceTable.Media_ic_camera_video_press); 
  6. }); 
  7.  
  8. private void startRecord() { 
  9.     if (cameraDevice == null) { 
  10.         HiLog.error(LABEL_LOG, "%{public}s""startRecord failed, parameters is illegal"); 
  11.         return
  12.     } 
  13.     synchronized (lock) { 
  14.         initMediaRecorder(); 
  15.         recorderSurface = mediaRecorder.getVideoSurface(); 
  16.         cameraConfigBuilder = cameraDevice.getCameraConfigBuilder(); 
  17.         try { 
  18.             cameraConfigBuilder.addSurface(previewSurface); 
  19.             if (recorderSurface != null) { 
  20.                 //添加界面作為相機流的輸出。 
  21.                 cameraConfigBuilder.addSurface(recorderSurface); 
  22.             } 
  23.             cameraDevice.configure(cameraConfigBuilder.build()); 
  24.         } catch (IllegalStateException | IllegalArgumentException e) { 
  25.             HiLog.error(LABEL_LOG, "%{public}s""startRecord IllegalStateException "); 
  26.         } 
  27.     } 
  28.     new ToastDialog(this).setText("Recording").show(); 

停止錄制

通過設置觸摸事件偵聽器setTouchEventListener()來觸發stopRecord(),實現停止錄制。

  1. //在組件中注冊觸摸事件的偵聽器。所有注冊的觀察員都將收到調度到組件的觸摸事件的通知。 
  2. videoRecord.setTouchEventListener((component, touchEvent) -> { 
  3.     if (touchEvent != null && touchEvent.getAction() == TouchEvent.PRIMARY_POINT_UP && isRecording) { 
  4.         stopRecord(); 
  5.         isRecording = false
  6.         videoRecord.setPixelMap(ResourceTable.Media_ic_camera_video_ready); 
  7.     } 
  8.     return true
  9. }); 
  10.  
  11. private void stopRecord() { 
  12.     synchronized (lock) { 
  13.         try { 
  14.             eventHandler.postTask(() -> mediaRecorder.stop());//stop():停止錄制。 
  15.             if (cameraDevice == null || cameraDevice.getCameraConfigBuilder() == null) { 
  16.                 HiLog.error(LABEL_LOG, "%{public}s""StopRecord cameraDevice or getCameraConfigBuilder is null"); 
  17.                 return
  18.             } 
  19.             cameraConfigBuilder = cameraDevice.getCameraConfigBuilder(); 
  20.             cameraConfigBuilder.addSurface(previewSurface); 
  21.             cameraConfigBuilder.removeSurface(recorderSurface); 
  22.             cameraDevice.configure(cameraConfigBuilder.build()); 
  23.         } catch (IllegalStateException | IllegalArgumentException exception) { 
  24.             HiLog.error(LABEL_LOG, "%{public}s""stopRecord occur exception"); 
  25.         } 
  26.     } 
  27.     new ToastDialog(this).setText("video saved").show(); 

視頻存儲和照片存儲類似,本文就不做贅述,更多相機的開發請參照HarmonyOS相機開發指導:

https://developer.harmonyos.com/cn/docs/documentation/doc-guides/media-camera-overview-0000000000031783

相機設備釋放

使用完相機后,必須通過release()來關閉相機和釋放資源,否則可能導致其他相機應用無法啟動。一旦相機被釋放,它所提供的操作就不能再被調用,否則會導致不可預期的結果,或是會引發狀態異常。相機設備釋放的示例代碼如下:

  1. private void releaseCamera() { 
  2.     if (cameraDevice != null) { 
  3.         //release():釋放攝像機。 
  4.         //釋放攝像機后,攝像機的所有操作都不可用。任何操作都會導致意外結果或異常。 
  5.         cameraDevice.release(); 
  6.     } 
  7.     if (imageReceiver != null) { 
  8.         imageReceiver.release(); 
  9.     } 

 至此,就完成了一個具有拍攝照片和錄制視頻功能的相機開發,開發者也可以通過合適的接口或者接口組合實現閃光燈控制、曝光時間控制、手動對焦和自動對焦控制、變焦控制、人臉識別以及更多的功能。

文章相關附件可以點擊下面的原文鏈接前往下載

相機示例程序的完整代碼.zip

想了解更多內容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術社區

https://harmonyos.51cto.com

 

責任編輯:jianghua 來源: 鴻蒙社區
相關推薦

2025-03-11 14:45:31

2011-12-19 20:54:28

iOS

2021-11-02 10:10:49

鴻蒙HarmonyOS應用

2023-05-15 16:12:32

GitHub項目

2010-03-22 15:06:05

WiMAX無線技術

2015-08-07 14:48:26

移動開發企業APPiUAP Mobile

2017-02-22 15:04:52

2025-04-14 00:00:00

MCPjson 信息地理編碼

2025-02-10 11:11:47

2012-03-07 14:37:03

JavaJavaMail

2024-05-16 10:59:16

Vue項目前端

2012-11-05 10:36:40

IBMdw

2025-03-03 10:00:00

2022-08-26 01:46:33

注冊中心NacosDNS

2018-08-31 21:59:53

2015-11-12 09:57:57

前端零基礎學習

2020-05-22 08:24:21

SQLMySQL數據庫

2023-05-30 14:58:05

智能開發鴻蒙

2023-05-26 16:01:32

驅動開發鴻蒙

2022-03-23 15:17:00

Harmony鴻蒙操作系統
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美精品一区二区三区在线播放 | 日韩不卡三区 | 97国产在线观看 | 国产精品毛片一区二区三区 | 国产欧美在线观看 | 久久99精品久久久水蜜桃 | 中国美女一级黄色片 | 羞羞网站免费观看 | 国产免费观看久久黄av片涩av | 日韩中文视频 | 色综合天天综合网国产成人网 | 欧美激情一区二区三级高清视频 | 伊人影院在线观看 | 2021狠狠干 | 久久久久亚洲精品中文字幕 | 日韩在线欧美 | 亚洲男女激情 | 精品欧美一区二区精品久久久 | 在线看无码的免费网站 | 天久久 | 男人天堂久久久 | 久久婷婷香蕉热狠狠综合 | 国产午夜精品理论片a大结局 | 国内精品久久久久 | 国产一区二区三区在线免费 | 中文在线a在线 | 91成人精品视频 | 日韩三级在线观看 | 最新高清无码专区 | 亚洲成av片人久久久 | 中文字幕中文字幕 | 青青久草 | 毛片网站免费观看 | 国产视频久久久久 | 中文字幕人成乱码在线观看 | 18av在线播放 | 久久久亚洲一区 | 午夜ww | 99视频免费在线 | 一区二区三区四区在线视频 | 国产精品黄 |