Explorar el Código

引用相机。webview注册多个方法,可以多次调用。

jiaxiaoqiang hace 9 meses
padre
commit
ec52bd5324

+ 10 - 1
entry/src/main/ets/entryability/EntryAbility.ets

@@ -4,9 +4,13 @@ import UIAbility from '@ohos.app.ability.UIAbility';
 import Want from '@ohos.app.ability.Want';
 import window from '@ohos.window';
 
+import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
+import { GlobalContext } from '../utils/GlobalThis';
+
 export default class EntryAbility extends UIAbility {
   onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
-    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
+    GlobalContext.getContext().setObject("context", this.context);
+    GlobalContext.getContext().setObject("pathDir", this.context.filesDir);
   }
 
   onDestroy(): void {
@@ -16,6 +20,11 @@ export default class EntryAbility extends UIAbility {
 
   onWindowStageCreate(windowStage: window.WindowStage): void {
 
+    let AtManager = abilityAccessCtrl.createAtManager();
+    AtManager.requestPermissionsFromUser(this.context, ['ohos.permission.READ_MEDIA', 'ohos.permission.WRITE_MEDIA',
+      'ohos.permission.CAMERA', 'ohos.permission.MICROPHONE', 'ohos.permission.START_INVISIBLE_ABILITY']).then(() => {
+    });
+
 
     // Main window is created, set main page for this ability
     hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

+ 488 - 0
entry/src/main/ets/model/CameraService.ts

@@ -0,0 +1,488 @@
+import camera from '@ohos.multimedia.camera'
+import deviceInfo from '@ohos.deviceInfo'
+import fileio from '@ohos.fileio'
+import image from '@ohos.multimedia.image'
+import media from '@ohos.multimedia.media'
+import mediaLibrary from '@ohos.multimedia.mediaLibrary'
+import Logger from '../utils/Logger'
+import MediaUtils from './MediaUtils'
+import ThumbnailGetter from './ThumbnailGetter'
+import { GlobalContext } from '../utils/GlobalThis'
+import { Context } from '@ohos.abilityAccessCtrl'
+
+const CameraSize = {
+  WIDTH: 1280,
+  HEIGHT: 720
+}
+const TAG = 'CameraService'
+
+class CameraService {
+  private mediaUtil = MediaUtils.getInstance()
+  private cameraManager: camera.CameraManager = undefined
+  cameras: Array<camera.CameraDevice> = undefined
+  private cameraInput: camera.CameraInput = undefined
+  private previewOutput: camera.PreviewOutput = undefined
+  private photoOutput: camera.PhotoOutput = undefined
+  private cameraOutputCapability: camera.CameraOutputCapability = undefined
+  private captureSession: camera.CaptureSession = undefined
+  private mReceiver: image.ImageReceiver = undefined
+  private videoPrepareFile: mediaLibrary.FileAsset = undefined
+  private mFileAssetId = 0
+  private avRecorder: media.AVRecorder = undefined
+  private videoOutput: camera.VideoOutput = undefined
+  private mThumbnailGetter = new ThumbnailGetter()
+  private mIsStartRecording = false
+  private handleTakePicture: (photoUri: string) => void = undefined
+  private videoConfig: any = {
+    videoSourceType: 1,
+    profile: {
+      fileFormat: 'mp4',
+      videoBitrate: 5000000,
+      videoCodec: 'video/avc',
+      videoFrameWidth: 640,
+      videoFrameHeight: 480,
+      videoFrameRate: 30
+    },
+    url: 'file:///data/media/01.mp4',
+    orientationHint: 0,
+    maxSize: 100,
+    maxDuration: 500,
+    rotation: 0
+  }
+  resolution: any = null
+  photoResolution: any = null
+  videoResolution: any = null
+
+  constructor() {
+  }
+
+  async savePicture(buffer: ArrayBuffer, img: image.Image) {
+    try {
+      Logger.info(TAG, 'savePicture')
+      let imgFileAsset = await this.mediaUtil.createAndGetUri(mediaLibrary.MediaType.IMAGE)
+      let imgPhotoUri = imgFileAsset.uri
+      Logger.info(TAG, `photoUri = ${imgPhotoUri}`)
+      let imgFd = await this.mediaUtil.getFdPath(imgFileAsset)
+      Logger.info(TAG, `fd = ${imgFd}`)
+      await fileio.write(imgFd, buffer)
+      await imgFileAsset.close(imgFd)
+      await img.release()
+      Logger.info(TAG, 'save image done')
+      if (this.handleTakePicture) {
+        this.handleTakePicture(imgPhotoUri)
+      }
+    } catch (err) {
+      Logger.error(TAG, `save picture err ${err.message}`)
+    }
+  }
+
+  public async createVideoFd(): Promise<number> {
+    Logger.info(TAG, `getVideoFd E`)
+    try {
+      let dataUri = await this.mediaUtil.createAndGetUri(mediaLibrary.MediaType.VIDEO)
+      this.videoPrepareFile = await this.mediaUtil.queryFile(dataUri);
+      const fdNumber = await this.videoPrepareFile.open('Rw')
+      return fdNumber;
+    } catch (err) {
+      Logger.error(TAG, `createVideoFd err: ` + err)
+    }
+    Logger.info(TAG, `getVideoFd X`)
+  }
+
+  async initCamera(surfaceId: number, cameraDeviceIndex: number, obj?, photoIndex?, previewObj?) {
+    try {
+      if (deviceInfo.deviceType === 'default') {
+        this.videoConfig.videoSourceType = 1
+      } else {
+        this.videoConfig.videoSourceType = 1
+      }
+      Logger.info(TAG, `cameraDeviceIndex success: ${cameraDeviceIndex}`)
+      await this.releaseCamera()
+      await this.getCameraManagerFn()
+      await this.getSupportedCamerasFn()
+      await this.getSupportedOutputCapabilityFn(cameraDeviceIndex)
+      if (previewObj) {
+        previewObj.format = this.cameraOutputCapability.previewProfiles[0].format
+        Logger.info(TAG, `previewObj format: ${previewObj.format}`)
+      }
+      await this.createPreviewOutputFn(previewObj ? previewObj : this.cameraOutputCapability.previewProfiles[0], surfaceId)
+      await this.createPhotoOutputFn(obj ? obj : this.cameraOutputCapability.photoProfiles[photoIndex?photoIndex:0])
+      await this.createCameraInputFn(this.cameras[cameraDeviceIndex])
+      await this.cameraInputOpenFn()
+      await this.sessionFlowFn()
+
+    } catch (err) {
+      Logger.error(TAG, 'initCamera err: ' + JSON.stringify(err.message))
+    }
+  }
+
+  setTakePictureCallback(callback) {
+    this.handleTakePicture = callback
+  }
+
+  // 拍照
+  async takePicture(imageRotation?) {
+    try {
+      Logger.info(TAG, 'takePicture start')
+      let photoSettings = {
+        rotation: imageRotation ? Number(imageRotation) : 0,
+        quality: 1,
+        location: {
+          latitude: 0,
+          longitude: 0,
+          altitude: 0
+        },
+        mirror: false
+      }
+      Logger.info(TAG, `photoOutput capture photoSettings: ` + JSON.stringify(photoSettings))
+      await this.photoOutput.capture(photoSettings)
+      Logger.info(TAG, 'takePicture end')
+    } catch (err) {
+      Logger.error(TAG, `takePicture fail err: ${JSON.stringify(err)}`)
+    }
+  }
+
+  public async createVideoOutput() {
+    Logger.info(TAG, `createVideoOutput start`)
+    this.mFileAssetId = await this.createVideoFd()
+    this.videoConfig.url = `fd://${this.mFileAssetId.toString()}`
+    await media.createAVRecorder().then((recorder) => {
+      Logger.info(TAG, `createVideoOutput createAVRecorder record: ${recorder}`)
+      this.avRecorder = recorder
+    })
+    if (this.avRecorder != null) {
+      this.avRecorder.on('error', (error) => {
+        if (error) {
+          Logger.error(TAG, `createVideoOutput error: ${JSON.stringify(error)}`)
+        }
+      })
+      Logger.info(TAG, `createVideoOutput size = ${JSON.stringify(this.cameraOutputCapability.videoProfiles[0].size)}`)
+      this.videoConfig.profile.videoFrameWidth = this.cameraOutputCapability.videoProfiles[0].size.width
+      this.videoConfig.profile.videoFrameHeight = this.cameraOutputCapability.videoProfiles[0].size.height
+      Logger.info(TAG, `createVideoOutput videoConfig: ` + JSON.stringify(this.videoConfig))
+      await this.avRecorder.prepare(this.videoConfig)
+      Logger.info(TAG, `createVideoOutput AVRecorder.prepare succeed.`)
+    } else {
+      Logger.error(TAG, `createVideoOutput createAVRecorder failed.`)
+      return
+    }
+
+    const videoId = await this.avRecorder.getInputSurface()
+    Logger.info(TAG, `createVideoOutput profileVideo =  ${JSON.stringify(this.cameraOutputCapability.videoProfiles[0])}.`)
+    try {
+      this.videoOutput = this.cameraManager.createVideoOutput(this.cameraOutputCapability.videoProfiles[0], videoId)
+    } catch (error) {
+      Logger.error(TAG, `createVideoOutput failed: ${JSON.stringify(error)}`)
+    }
+    Logger.info(TAG, `createVideoOutput end`)
+  }
+
+  public async releaseVideoOutput() {
+    Logger.info(TAG, `releaseVideoOutput start`)
+    if (this.videoOutput) {
+      Logger.info(TAG, `LoggerreleaseVideoOutput start`)
+      try {
+        await this.videoOutput.release()
+      } catch (error) {
+        Logger.error(TAG, `LoggerreleaseVideoOutput failed: ${JSON.stringify(error)}`)
+      }
+      Logger.info(TAG, `LoggerreleaseVideoOutput end`)
+      this.videoOutput = null
+    }
+    Logger.info(TAG, `releaseVideoOutput end`)
+  }
+
+  // 开始录制
+  async StartRecording() {
+    try {
+      Logger.info(TAG, `StartRecording begin`)
+      await this.captureSession.stop()
+      this.captureSession.beginConfig()
+      this.captureSession.removeOutput(this.photoOutput)
+      Logger.info(TAG, `StartRecording removeOutput finished.`)
+      if (this.videoOutput) {
+        await this.captureSession.removeOutput(this.videoOutput)
+        Logger.info(TAG, `old videoOutput has been removed.`)
+      }
+      await this.createVideoOutput()
+      this.captureSession.addOutput(this.videoOutput)
+      Logger.info(TAG, `StartRecording addOutput finished.`)
+      await this.captureSession.commitConfig()
+      Logger.info(TAG, `StartRecording commitConfig finished.`)
+      await this.captureSession.start()
+      Logger.info(TAG, `StartRecording Session.start finished.`)
+    } catch (err) {
+      Logger.error(TAG, `remove videoOutput ${JSON.stringify(err)}`)
+    }
+    await this.videoOutput.start().then(() => {
+      Logger.info(TAG, `videoOutput.start()`)
+    })
+    await this.avRecorder.start().then(() => {
+      Logger.info(TAG, `AVRecorder.start()`)
+    })
+    this.mIsStartRecording = true
+    Logger.info(TAG, `StartRecording end`)
+  }
+
+  // 停止录制
+  async stopRecording() {
+    if (!this.videoOutput || !this.avRecorder) {
+      Logger.error(TAG, `stopRecording error videoOutPut: ${this.videoOutput},AVRecorder: ${this.avRecorder} .`)
+      return
+    }
+    this.mIsStartRecording = false
+    try {
+      await this.avRecorder.stop()
+      await this.avRecorder.release()
+    } catch (err) {
+      Logger.error(TAG, `stop AVRecorder ${err}`)
+    }
+
+    try {
+      await this.videoOutput.stop()
+    } catch (err) {
+      Logger.error(TAG, `stop videoOutput ${err}`)
+    }
+
+    if (this.mFileAssetId != undefined) {
+      await this.videoPrepareFile.close(this.mFileAssetId)
+      this.mFileAssetId = undefined
+      Logger.info(TAG, `fileAsset.close().`)
+    }
+
+    const thumbnailPixelMap = await this.mThumbnailGetter.getThumbnailInfo(640, 480)
+    Logger.info(TAG, `stopRecording invoke X.`)
+    return thumbnailPixelMap
+  }
+
+  // 查询相机设备在模式下支持的输出能力
+  async getSupportedOutputCapabilityFn(cameraDeviceIndex) {
+    Logger.info(TAG, `cameraOutputCapability cameraId: ${this.cameras[cameraDeviceIndex].cameraId}`)
+    this.cameraOutputCapability = this.cameraManager.getSupportedOutputCapability(this.cameras[cameraDeviceIndex])
+    let previewSize = []
+    let photoSize = []
+    let videoSize = []
+    this.cameraOutputCapability.previewProfiles.forEach((item, index) => {
+      Logger.info(TAG, `cameraOutputCapability previewProfiles index: ${index}, item:` + JSON.stringify(item))
+      previewSize.push({
+        value: `${item.size.width}x${item.size.height}`
+      })
+    })
+    this.cameraOutputCapability.photoProfiles.forEach((item, index) => {
+      Logger.info(TAG, `cameraOutputCapability photoProfiles index: ${index}, item:` + JSON.stringify(item))
+      photoSize.push({
+        value: `${item.size.width}x${item.size.height}`
+      })
+    })
+    this.cameraOutputCapability.videoProfiles.forEach((item, index) => {
+      Logger.info(TAG, `cameraOutputCapability videoProfiles index: ${index}, item:` + JSON.stringify(item))
+      videoSize.push({
+        value: `${item.size.width}x${item.size.height}`
+      })
+    })
+    Logger.info(TAG, `cameraOutputCapability previewProfiles:` + JSON.stringify(this.cameraOutputCapability.previewProfiles))
+    Logger.info(TAG, `cameraOutputCapability photoProfiles:` + JSON.stringify(this.cameraOutputCapability.photoProfiles))
+    Logger.info(TAG, `cameraOutputCapability videoProfiles:` + JSON.stringify(this.cameraOutputCapability.videoProfiles))
+    Logger.info(TAG, `cameraOutputCapability previewProfiles previewSize:` + JSON.stringify(previewSize))
+    this.resolution = previewSize
+    this.photoResolution = photoSize
+    this.videoResolution = videoSize
+    return previewSize
+  }
+
+  public async releaseRecording() {
+    Logger.info(TAG, `releaseRecording start`)
+    if (!this.avRecorder) {
+      Logger.info(TAG, `AVRecorder has not been created.`)
+      return
+    }
+    if (this.mIsStartRecording) {
+      await this.stopRecording()
+    }
+    await this.avRecorder.release().then(() => {
+      Logger.info(TAG, `AVRecorder.release() success.`)
+      this.avRecorder = undefined
+    })
+    Logger.info(TAG, `releaseRecording end`)
+  }
+
+  // 释放会话及其相关参数
+  async releaseCamera() {
+    Logger.info(TAG, `releaseCamera start`)
+    await this.releaseRecording()
+    await this.releaseVideoOutput()
+    await this.releasePhotoOutput()
+    await this.releaseSession()
+    Logger.info(TAG, `releaseCamera end`)
+  }
+
+  // 释放会话
+  async releaseSession() {
+    Logger.info(TAG, `releaseSession start`)
+    if (this.captureSession) {
+      try {
+        await this.captureSession.stop()
+        await this.captureSession.release()
+        this.captureSession = null
+      } catch (error) {
+        Logger.error(TAG, `releaseSession failed: ${JSON.stringify(error)}`)
+      }
+    }
+    Logger.info(TAG, `releaseSession end`)
+  }
+
+  // 获取相机管理器实例
+  async getCameraManagerFn() {
+    try {
+      this.cameraManager = camera.getCameraManager(GlobalContext.getContext().getObject("context") as Context)
+      Logger.info(TAG, `getCameraManager success: ` + JSON.stringify(this.cameraManager))
+    } catch (err) {
+      Logger.error(TAG, `getCameraManagerFn fail err: ${err}, message: ${err.message}, code: ${err.code}`)
+    }
+  }
+
+  // 获取支持指定的相机设备对象
+  async getSupportedCamerasFn() {
+    try {
+      this.cameras = this.cameraManager.getSupportedCameras()
+      if (this.cameras) {
+        Logger.info(TAG, `getCameras success.`)
+        for (let i = 0; i < this.cameras.length; i++) {
+          Logger.info(TAG, `--------------Camera Info-------------`)
+          Logger.info(TAG, `camera_id: ${this.cameras[i].cameraId}`)
+          Logger.info(TAG, `cameraPosition: ${this.cameras[i].cameraPosition}`)
+          Logger.info(TAG, `cameraType: ${this.cameras[i].cameraType}`)
+          Logger.info(TAG, `connectionType: ${this.cameras[i].connectionType}`)
+        }
+      }
+    } catch (err) {
+      Logger.error(TAG, `getSupportedCamerasFn fail err: ${err}, message: ${err.message}, code: ${err.code}`)
+    }
+  }
+
+  // 创建previewOutput输出对象
+  async createPreviewOutputFn(previewProfilesObj, surfaceId) {
+    try {
+      Logger.info(TAG, `createPreviewOutputFn previewProfilesObj success: ` + JSON.stringify(previewProfilesObj))
+      this.previewOutput = this.cameraManager.createPreviewOutput(previewProfilesObj, surfaceId.toString())
+      Logger.info(TAG, `createPreviewOutputFn success: ` + JSON.stringify(this.previewOutput))
+    } catch (err) {
+      Logger.error(TAG, `createPreviewOutputFn fail err: ${err}, message: ${err.message}, code: ${err.code}`)
+    }
+  }
+
+  // 创建photoOutput输出对象
+  async createPhotoOutputFn(photoProfileObj) {
+    try {
+      Logger.info(TAG, `createPhotoOutputFn photoProfileObj success: ` + JSON.stringify(photoProfileObj))
+      try {
+        this.mReceiver = image.createImageReceiver(CameraSize.WIDTH, CameraSize.HEIGHT, image.ImageFormat.JPEG, 8)
+        Logger.info(TAG, 'createImageReceiver')
+        this.mReceiver.on('imageArrival', () => {
+          Logger.info(TAG, 'imageArrival')
+          this.mReceiver.readNextImage((err, image) => {
+            Logger.info(TAG, 'readNextImage')
+            if (err || image === undefined) {
+              Logger.error(TAG, 'failed to get valid image')
+              return
+            }
+            image.getComponent(4, (errMsg, img) => {
+              Logger.info(TAG, 'getComponent')
+              if (errMsg || img === undefined) {
+                Logger.info(TAG, 'failed to get valid buffer')
+                return
+              }
+              let buffer
+              if (img.byteBuffer) {
+                buffer = img.byteBuffer
+              } else {
+                Logger.error(TAG, 'img.byteBuffer is undefined')
+              }
+              this.savePicture(buffer, image)
+            })
+          })
+        })
+      } catch (err) {
+        Logger.error(TAG, `image Receiver err ${err.message}`)
+      }
+      let mSurfaceId = await this.mReceiver.getReceivingSurfaceId()
+      this.photoOutput = this.cameraManager.createPhotoOutput(photoProfileObj, mSurfaceId)
+      Logger.info(TAG, `createPhotoOutputFn success: ` + JSON.stringify(this.photoOutput))
+    } catch (err) {
+      Logger.error(TAG, `createPhotoOutputFn fail err: ${err}, message: ${err.message}, code: ${err.code}`)
+    }
+  }
+
+  public async releasePhotoOutput() {
+    Logger.info(TAG, `releasePhotoOutput start`)
+    if (this.photoOutput) {
+      try {
+        await this.photoOutput.release()
+        this.photoOutput = null
+      } catch (error) {
+        Logger.error(TAG, `releasePhotoOutput failed: ${JSON.stringify(error)}`)
+      }
+    }
+    if (this.mReceiver) {
+      await this.mReceiver.release()
+      this.mReceiver = null
+    }
+    Logger.info(TAG, `releasePhotoOutput end`)
+  }
+
+  // 创建cameraInput输出对象
+  async createCameraInputFn(cameraDeviceIndex) {
+    try {
+      this.cameraInput = this.cameraManager.createCameraInput(cameraDeviceIndex)
+      Logger.info(TAG, `createCameraInputFn success: ${this.cameraInput}`)
+    } catch (err) {
+      Logger.error(TAG, `createCameraInputFn fail err: ${err}, message: ${err.message}, code: ${err.code}`)
+    }
+  }
+
+  // 打开相机
+  async cameraInputOpenFn() {
+    await this.cameraInput.open()
+      .then((data) => {
+        Logger.info(TAG, `cameraInputOpenFn open success: ${data}`)
+      })
+      .catch((err) => {
+        Logger.error(TAG, `cameraInputOpenFn fail err: ${err}, message: ${err.message}, code: ${err.code}`)
+      })
+  }
+
+  // 会话流程
+  async sessionFlowFn() {
+    // 创建captureSession实例
+    this.captureSession = this.cameraManager.createCaptureSession()
+    Logger.info(TAG, `createSession captureSession: ${this.captureSession}, cameraInput: ${this.cameraInput}, videoOutPut: ${this.videoOutput}, photoOutPut: ${this.photoOutput},  mPreviewOutput: ${this.previewOutput}`)
+    // 开始配置会话
+    Logger.info(TAG, `createSession beginConfig.`)
+    try {
+      this.captureSession.beginConfig()
+      await new Promise((resolve) => setTimeout(resolve, 1));
+      // cameraInput加入会话
+      Logger.info(TAG, `createSession addInput.`)
+      this.captureSession.addInput(this.cameraInput)
+      // photoOutput加入会话
+      Logger.info(TAG, `createSession photo addOutput.`)
+      this.captureSession.addOutput(this.photoOutput)
+      // previewOutput加入会话
+      Logger.info(TAG, `createSession preview addOutput.`)
+      this.captureSession.addOutput(this.previewOutput)
+    } catch (err) {
+      Logger.error(TAG, `Error in camera operation: ${JSON.stringify(err)}`)
+    }
+    try {
+      // 提交配置会话
+      await this.captureSession.commitConfig()
+      // 开启会话
+      await this.captureSession.start()
+    } catch (err) {
+      Logger.error(TAG, `Failed to open camera: ${JSON.stringify(err)}`)
+    }
+    Logger.info(TAG, `sessionFlowFn end`)
+  }
+}
+
+export default new CameraService()

+ 195 - 0
entry/src/main/ets/model/MediaUtils.ts

@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import mediaLibrary from '@ohos.multimedia.mediaLibrary'
+import { Context } from '@ohos.abilityAccessCtrl'
+import Logger from '../utils/Logger'
+import { GlobalContext } from '../utils/GlobalThis'
+import DateTimeUtil from '../utils/DateTimeUtil'
+
+const TAG = 'MediaUtils'
+
+export default class MediaUtils {
+  private mediaTest: mediaLibrary.MediaLibrary = mediaLibrary.getMediaLibrary(GlobalContext.getContext().getObject("context") as Context)
+  private static instance: MediaUtils = new MediaUtils()
+
+  public static getInstance() {
+    if (this.instance === undefined) {
+      this.instance = new MediaUtils()
+    }
+    return this.instance
+  }
+
+  async createAndGetUri(mediaType: number) {
+    let info = this.getInfoFromType(mediaType)
+    let dateTimeUtil = new DateTimeUtil()
+    let name = `${dateTimeUtil.getDate()}_${dateTimeUtil.getTime()}`
+    let displayName = `${info.prefix}${name}${info.suffix}`
+    Logger.info(TAG, `displayName = ${displayName},mediaType = ${mediaType}`)
+    Logger.info(TAG, `info.directory = ${info.directory}`)
+    let publicPath = await this.mediaTest.getPublicDirectory(info.directory)
+    Logger.info(TAG, `publicPath = ${publicPath}`)
+    try {
+      return await this.mediaTest.createAsset(mediaType, displayName, publicPath)
+    } catch (err) {
+      Logger.info(TAG, `createAsset err ` + JSON.stringify(err))
+    }
+  }
+
+  async queryFile(dataUri: any) {
+    let fileKeyObj = mediaLibrary.FileKey
+    if (dataUri !== undefined) {
+      let args = dataUri.id.toString()
+      let fetchOp = {
+        selections: `${fileKeyObj.ID}=?`,
+        selectionArgs: [args],
+      }
+      const fetchFileResult = await this.mediaTest.getFileAssets(fetchOp)
+      Logger.info(TAG, `fetchFileResult.getCount() = ${fetchFileResult.getCount()}`)
+      const fileAsset = await fetchFileResult.getFirstObject()
+      return fileAsset
+    }
+  }
+
+  async getFdPath(fileAsset: any) {
+    let fd = await fileAsset.open('Rw')
+    Logger.info(TAG, `fd = ${fd}`)
+    return fd
+  }
+
+  async getFileAssetsAlbum(path) {
+    let fileKeyObj = mediaLibrary.FileKey
+    // ALBUM_NAME
+    let fetchOp = {
+      selections: `${fileKeyObj.RELATIVE_PATH}=?`,
+      selectionArgs: [`${path}`],
+    }
+    const fetchFileResult = await this.mediaTest.getFileAssets(fetchOp)
+    Logger.info(TAG, `getFileAssetsAlbum,fetchFileResult.count = ${fetchFileResult.getCount()}`)
+    let fileAssets: Array<mediaLibrary.FileAsset> = []
+    if (fetchFileResult.getCount() > 0) {
+      fileAssets = await fetchFileResult.getAllObject()
+    }
+    return fileAssets
+  }
+
+  async getFileAssetsFromType(mediaType: number) {
+    Logger.info(TAG, `getFileAssetsFromType,mediaType = ${mediaType}`)
+    let fileKeyObj = mediaLibrary.FileKey
+    // ALBUM_NAME
+    let fetchOp = {
+      selections: `${fileKeyObj.MEDIA_TYPE}=?`,
+      selectionArgs: [`${mediaType}`],
+    }
+    const fetchFileResult = await this.mediaTest.getFileAssets(fetchOp)
+    Logger.info(TAG, `getFileAssetsFromType,fetchFileResult.count = ${fetchFileResult.getCount()}`)
+    let fileAssets = []
+    if (fetchFileResult.getCount() > 0) {
+      fileAssets = await fetchFileResult.getAllObject()
+    }
+    return fileAssets
+  }
+
+  async getAlbums() {
+    Logger.info(TAG, 'getAlbums begin')
+    let albums = []
+    const [ files, images, videos, audios ] = await Promise.all([
+    this.getFileAssetsFromType(mediaLibrary.MediaType.FILE),
+    this.getFileAssetsFromType(mediaLibrary.MediaType.IMAGE),
+    this.getFileAssetsFromType(mediaLibrary.MediaType.VIDEO),
+    this.getFileAssetsFromType(mediaLibrary.MediaType.AUDIO)
+    ])
+    albums.push({
+      albumName: 'Documents', count: files.length, mediaType: mediaLibrary.MediaType.FILE
+    })
+    albums.push({
+      albumName: 'Pictures', count: images.length, mediaType: mediaLibrary.MediaType.IMAGE
+    })
+    albums.push({
+      albumName: 'Videos', count: videos.length, mediaType: mediaLibrary.MediaType.VIDEO
+    })
+    albums.push({
+      albumName: 'Audios', count: audios.length, mediaType: mediaLibrary.MediaType.AUDIO
+    })
+    return albums
+  }
+
+  deleteFile(media: any) {
+    let uri = media.uri
+    Logger.info(TAG, `deleteFile,uri = ${uri}`)
+    // @ts-ignore
+    return this.mediaTest.deleteAsset(uri)
+  }
+
+  onDateChange(callback: () => void) {
+    this.mediaTest.on('albumChange', () => {
+      Logger.info(TAG, 'albumChange called')
+      callback()
+    })
+    this.mediaTest.on('imageChange', () => {
+      Logger.info(TAG, 'imageChange called')
+      callback()
+    })
+    this.mediaTest.on('audioChange', () => {
+      Logger.info(TAG, 'audioChange called')
+      callback()
+    })
+    this.mediaTest.on('videoChange', () => {
+      Logger.info(TAG, 'videoChange called')
+      callback()
+    })
+    this.mediaTest.on('fileChange', () => {
+      Logger.info(TAG, 'fileChange called')
+      callback()
+    })
+  }
+
+  offDateChange() {
+    this.mediaTest.off('albumChange')
+    this.mediaTest.off('imageChange')
+    this.mediaTest.off('audioChange')
+    this.mediaTest.off('videoChange')
+    this.mediaTest.off('fileChange')
+  }
+
+  getInfoFromType(mediaType: number) {
+    let result = {
+      prefix: '', suffix: '', directory: 0
+    }
+    switch (mediaType) {
+      case mediaLibrary.MediaType.FILE:
+        result.prefix = 'FILE_'
+        result.suffix = '.txt'
+        result.directory = mediaLibrary.DirectoryType.DIR_DOCUMENTS
+        break
+      case mediaLibrary.MediaType.IMAGE:
+        result.prefix = 'IMG_'
+        result.suffix = '.jpg'
+        result.directory = mediaLibrary.DirectoryType.DIR_IMAGE
+        break
+      case mediaLibrary.MediaType.VIDEO:
+        result.prefix = 'VID_'
+        result.suffix = '.mp4'
+        result.directory = mediaLibrary.DirectoryType.DIR_CAMERA
+        break
+      case mediaLibrary.MediaType.AUDIO:
+        result.prefix = 'AUD_'
+        result.suffix = '.wav'
+        result.directory = mediaLibrary.DirectoryType.DIR_AUDIO
+        break
+    }
+    return result
+  }
+}

+ 59 - 0
entry/src/main/ets/model/ThumbnailGetter.ts

@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2023 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import mediaLibrary from '@ohos.multimedia.mediaLibrary'
+import { Context } from '@ohos.abilityAccessCtrl'
+import Logger from '../utils/Logger'
+import { GlobalContext } from '../utils/GlobalThis'
+import image from '@ohos.multimedia.image';
+
+
+export default class ThumbnailGetter {
+  private TAG = '[ThumbnailGetter]:'
+
+  public async getThumbnailInfo(width: number, height: number, uri?: string): Promise<image.PixelMap | undefined> {
+    Logger.info(`${this.TAG} getThumbnailInfo E`)
+    Logger.debug(`${this.TAG} getThumbnailInfo width: ${width}, height: ${height}, uri: ${JSON.stringify(uri)}`)
+    const fileKeyObj = mediaLibrary.FileKey;
+    let fetchOp: any
+    const media = mediaLibrary.getMediaLibrary(GlobalContext.getContext().getObject("context") as Context);
+    let publicPath: string = await media.getPublicDirectory(mediaLibrary.DirectoryType.DIR_CAMERA)
+    Logger.info(`${this.TAG} getThumbnailInfo media: ${media}`)
+    fetchOp = {
+      selections: `${fileKeyObj.RELATIVE_PATH}=?`,
+      selectionArgs: [publicPath],
+      order: `${fileKeyObj.DATE_ADDED} DESC LIMIT 0, 1`
+    }
+
+    Logger.info(`${this.TAG} getThumbnailInfo fetchOp: ${JSON.stringify(fetchOp)}`)
+    const fetchFileResult = await media.getFileAssets(fetchOp);
+    const count = fetchFileResult.getCount()
+    Logger.info(`${this.TAG} getThumbnailInfo fetchFileResult.getCount: ${count}`)
+    if (count == 0) {
+      return undefined
+    }
+    const lastFileAsset = await fetchFileResult.getLastObject()
+    await fetchFileResult.close()
+    if (lastFileAsset == null) {
+      Logger.error(`${this.TAG} getThumbnailInfo lastFileAsset is null`)
+      return undefined
+    }
+    const thumbnailPixelMap = lastFileAsset.getThumbnail({
+      width: width, height: height
+    })
+    Logger.info(`${this.TAG} getThumbnailInfo thumbnailPixelMap: ${JSON.stringify(thumbnailPixelMap)} X`)
+    return thumbnailPixelMap
+  }
+}

+ 0 - 17
entry/src/main/ets/pages/CamerPage.ets

@@ -1,17 +0,0 @@
-@Entry
-@Component
-struct CamerPage {
-  @State message: string = 'Hello World';
-
-  build() {
-    Row() {
-      Column() {
-        Text(this.message)
-          .fontSize(50)
-          .fontWeight(FontWeight.Bold)
-      }
-      .width('100%')
-    }
-    .height('100%')
-  }
-}

+ 155 - 0
entry/src/main/ets/pages/CameraPage.ets

@@ -0,0 +1,155 @@
+import router from '@ohos.router'
+import common from '@ohos.app.ability.common'
+import CameraService from '../model/CameraService'
+import Logger from '../utils/Logger'
+import { GlobalContext } from '../utils/GlobalThis'
+import promptAction from '@ohos.promptAction'
+import { BusinessError } from '@ohos.base'
+import http from '@ohos.net.http'
+import { FormData, File, FileUpload } from "@ohos/commons-fileupload"
+import fs from '@ohos.file.fs';
+import { ProgressDialog } from '../components/ProgressDialog';
+import uploadInstance from '../utils/UploadUtil'
+
+const TAG = "uploadTagegggg"
+
+@Entry
+@Component
+struct Index {
+  private mXComponentController: XComponentController = new XComponentController()
+  @State surfaceId: number = 0;
+  @State cameraDeviceIndex: number = 0
+  @State assetUri?: string = undefined //拍照返回的
+  @State thumbnail: PixelMap | undefined = undefined //录像返回的
+  @State isTakePictureEnabled: boolean = true
+  @State isTakeVideoEnabled: boolean = true
+  @State captureBtnScale: number = 1
+  @State isUploading: boolean = false
+
+  async aboutToAppear() {
+    CameraService.setTakePictureCallback((assetUri: string): void => this.handleTakePicture(assetUri))
+    Logger.info(TAG, `takePicture end, assetUri: ${this.assetUri}`)
+  }
+
+  async cameraInit() {
+    CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex).then(() => {
+    })
+  }
+
+  handleTakePicture(assetUri: string) {
+    this.assetUri = assetUri
+    // Logger.info(TAG, `takePicture end, assetUri: ${this.assetUri}`)
+
+    this.isUploading = true
+    uploadInstance.startUpload(assetUri, () => {
+      this.isUploading = false
+      console.log(TAG, "上传完成后的callback")
+    })
+
+
+  }
+
+  onPageShow() {
+    let SurfaceId: string = this.mXComponentController.getXComponentSurfaceId()
+    this.surfaceId = Number.parseInt(SurfaceId)
+    CameraService.initCamera(this.surfaceId, this.cameraDeviceIndex)
+    Logger.info(TAG, `OnPageShow this.cameraDeviceIndex ${this.cameraDeviceIndex}`)
+  }
+
+  onPageHide() {
+    CameraService.releaseCamera()
+    Logger.info(TAG, `onPageHide releaseCamera end`)
+  }
+
+  build() {
+    Stack({ alignContent: Alignment.BottomEnd }) {
+      XComponent({
+        id: 'componentId',
+        type: 'surface',
+        controller: this.mXComponentController
+      })
+        .size({ width: '100%', height: '100%' })
+        .onLoad(async () => {
+          Logger.info(TAG, 'onLoad is called')
+          let SurfaceId: string = this.mXComponentController.getXComponentSurfaceId()
+          this.surfaceId = Number.parseInt(SurfaceId)
+          Logger.info(TAG, `onLoad surfaceId: ${this.surfaceId}`)
+          this.cameraInit()
+        })
+
+      // 拍照完成后显示的image。
+      Row() {
+        if (this.assetUri !== undefined) {
+
+          Stack({ alignContent: Alignment.Center }) {
+            Image(this.assetUri)
+              .size({ height: '100%' })
+              .border({ width: 1, color: Color.White })
+            if (this.isUploading) {
+              Column() {
+                Text('正在上传中...').fontSize(22).margin({ top: 10, bottom: 10 })
+                LoadingProgress()
+                  .color(Color.Blue)
+                  .layoutWeight(1)
+              }
+              .height(140)
+              .width(150)
+              .backgroundColor(Color.White)
+              .borderRadius(10)
+            }
+          }
+        }
+
+      }.size({ width: '100%', height: '30%' }).justifyContent(FlexAlign.SpaceBetween)
+
+      Row() {
+        Stack({ alignContent: Alignment.Center }) {
+          Image($r('app.media.ic_circled')).fillColor(Color.White)
+          Image($r('app.media.ic_circled_filled'))
+            .width(54)
+            .aspectRatio(1)
+            .fillColor(Color.White)
+            .scale({ x: this.captureBtnScale, y: this.captureBtnScale, z: this.captureBtnScale })
+            .enabled(this.isTakePictureEnabled)
+            .onTouch(async (event: TouchEvent) => {
+              if (event.type === TouchType.Down) {
+                animateTo(
+                  { duration: 125, curve: Curve.Sharp, delay: 0 },
+                  () => {
+                    this.captureBtnScale = 0.85
+                  })
+              } else if (event.type === TouchType.Up) {
+                animateTo(
+                  { duration: 125, curve: Curve.Sharp, delay: 0,
+                    onFinish: () => {
+                      this.captureBtnScale = 1
+                    } },
+                  () => {
+                    this.captureBtnScale = 1
+                  })
+                this.isTakePictureEnabled = false
+                CameraService.takePicture()
+                this.isTakePictureEnabled = true
+              }
+            })
+        }.width(76).aspectRatio(1)
+      }.size({ width: '100%', height: 76 }).justifyContent(FlexAlign.Center)
+
+      Row() {
+        Image($r("app.media.back_white")).width(20).height(20)
+        Text("返回").fontColor(Color.White).fontSize(20).margin({ left: 5 })
+      }
+      .position({ x: 10, y: 10 })
+      .onClick(() => {
+        router.back()
+      })
+
+    }.width('100%').height('100%').backgroundColor(Color.Black)
+    .gesture(
+      PanGesture({ direction: PanDirection.Left | PanDirection.Right })
+        .onActionEnd(() => {
+          router.back()
+        })
+    )
+  }
+}

+ 88 - 66
entry/src/main/ets/pages/Index.ets

@@ -9,6 +9,8 @@ import { BusinessError } from '@ohos.base';
 import { FormData, File, FileUpload } from "@ohos/commons-fileupload"
 import fs from '@ohos.file.fs';
 import { ProgressDialog } from '../components/ProgressDialog';
+import router from '@ohos.router';
+import uploadInstance from '../utils/UploadUtil';
 
 
 interface DownStartModel {
@@ -52,7 +54,7 @@ class BridgeModel {
   }
 
   // this.controller.registerJavaScriptProxy 这个里面要对应
-  download(params: string): string {
+  download(params: string): void {
     // download(value: string, params: BridgeParams): string {
     // let downloadUrl: string = baseUrl + proxyPrefix + params.path
     // console.info(TAG, `download:`, downloadUrl);
@@ -61,10 +63,19 @@ class BridgeModel {
     let p: BridgeParams = JSON.parse(params)
 
 
-    return 'ArkTS收到了下载的请求';
+    // return true;
+  }
+
+  selectFile(params: string): void {
+    console.info(TAG, `selectFile:`, params);
+  }
+
+  startCamera(params: string): void {
+    console.info(TAG, `startCamera:`, params);
   }
 }
 
+
 @Entry
 @Component
 struct Index {
@@ -86,7 +97,8 @@ struct Index {
 
     // 这个必须要调用刷新才起作用, 而且只能执行一次
     if (!this.hasRegistered) {
-      this.controller.registerJavaScriptProxy(this.bridgeObj, TAG, ["download"])
+      console.info(TAG, `registerJavaScriptProxy:`);
+      this.controller.registerJavaScriptProxy(this.bridgeObj, TAG, ["download", "selectFile", "startCamera"])
       this.controller.refresh()
       this.hasRegistered = true
     }
@@ -142,73 +154,79 @@ struct Index {
 
         // this.uploadImage(result.photoUris); file://media/Photo/3/IMG_1723222627_002/IMG_20240810_005707.jpg
         result.photoUris.forEach((url) => {
-          console.log("uploadLog: 选择完图片的路径" + url);
-
-          try {
-            const uri = url
-            // 2.2 根据uri同步打开文件
-            const file = fs.openSync(uri)
-            // 2.3 同步获取文件的详细信息
-            const stat = fs.statSync(file.fd)
-            // 2.4 创建缓冲区存储读取的文件流
-            const buffer = new ArrayBuffer(stat.size)
-            // 2.5 开始同步读取文件流到缓冲区
-            fs.readSync(file.fd, buffer)
-            // 2.6 关闭文件流
-            fs.closeSync(file)
-
-            // 3. 转成base64编码的字符串
-            // const helper = new util.Base64Helper()
-            // const str = helper.encodeToStringSync(new Uint8Array(buffer))
-            console.log('mk-logger', 'photoPlugin-str', buffer.byteLength, JSON.stringify(buffer))
-
-            let toUpFile = new File()
-            toUpFile.fileName = "test.jpg"
-            toUpFile.fileData = buffer
-
-            let fileUpload = new FileUpload({
-              baseUrl: "http://10.88.11.200:8078",
-              readTimeout: 60000,
-              connectTimeout: 60000,
-            })
+          // console.log("uploadLog: 选择完图片的路径" + url);
 
-            const formData = new FormData();
-            // formData.append("key", 1); //可以添加基本类型的值,目前支持string、number
-            formData.append("fileName", "test.jpg"); //也可以添加File类型的对象
-            // formData.append('file', `internal://cache/${fileName}`)
-            formData.append('file', toUpFile)
-
-            fileUpload.post("/api/v1/base/upload", formData, {
-
-              header: {
-                'Content-Type': 'multipart/form-data',
-                'Authorization': "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOnsiaWQiOjEwMDAwLCJ1c2VyTmFtZSI6ImFkbWluIiwiZGVwdElkIjoxLCJzdGF0aW9uSWQiOjAsImF2YXRhciI6Ii9qZ2ZpbGUvLzIwMjQvNS8yNy8yNzQzMjkzOTU4Mzg4NTIuanBnIiwib3JnSWQiOjF9LCJkZXZpY2UiOiJiYWNrIiwiZWZmIjoxNzIzOTQ2NTQwNzQxLCJyblN0ciI6InpkOWpKZFlBdVpnR0NEd2xBWnZIcXpkUThBaW9xaUh6In0.8fEZh6HCbkE0kmwF6Ru-1JtVSfQN39mB51pIsI6bzDI"
-              },
-            }).then((res: http.HttpResponse) => {
-              this.dialogController.close()
-              let model: FileResponseModel = res.result as FileResponseModel
-
-              // let data: FileModel = JSON.parse(model.data)
-
-              console.log(TAG, "ddddddd success", JSON.stringify(model));
-
-              // let data: ESObject = res.result as ESObject
-              // // this.netImageUrl = data.data.fileUrl ?? ""
-              // console.error("ddddddd    图片地址:  ", `http://10.88.11.201:9000/${data.data.fileUrl}`);
-            }).catch((err: BusinessError) => {
-              this.dialogController.close()
-              console.error(TAG, "ddddddd    fail");
-            })
-          }
-          catch (e) {
+          uploadInstance.startUpload(url, () => {
             this.dialogController.close()
-            console.log(TAG, 'mk-logger', 'photoPlugin-str', JSON.stringify(e))
-          }
+          })
+
+          // try {
+          //   const uri = url
+          //   // 2.2 根据uri同步打开文件
+          //   const file = fs.openSync(uri)
+          //   // 2.3 同步获取文件的详细信息
+          //   const stat = fs.statSync(file.fd)
+          //   // 2.4 创建缓冲区存储读取的文件流
+          //   const buffer = new ArrayBuffer(stat.size)
+          //   // 2.5 开始同步读取文件流到缓冲区
+          //   fs.readSync(file.fd, buffer)
+          //   // 2.6 关闭文件流
+          //   fs.closeSync(file)
+          //
+          //   // 3. 转成base64编码的字符串
+          //   // const helper = new util.Base64Helper()
+          //   // const str = helper.encodeToStringSync(new Uint8Array(buffer))
+          //   console.log('mk-logger', 'photoPlugin-str', buffer.byteLength, JSON.stringify(buffer))
+          //
+          //   let toUpFile = new File()
+          //   toUpFile.fileName = "test.jpg"
+          //   toUpFile.fileData = buffer
+          //
+          //   let fileUpload = new FileUpload({
+          //     baseUrl: "http://10.88.11.200:8078",
+          //     readTimeout: 60000,
+          //     connectTimeout: 60000,
+          //   })
+          //
+          //   const formData = new FormData();
+          //   // formData.append("key", 1); //可以添加基本类型的值,目前支持string、number
+          //   formData.append("fileName", "test.jpg"); //也可以添加File类型的对象
+          //   // formData.append('file', `internal://cache/${fileName}`)
+          //   formData.append('file', toUpFile)
+          //
+          //   fileUpload.post("/api/v1/base/upload", formData, {
+          //
+          //     header: {
+          //       'Content-Type': 'multipart/form-data',
+          //       'Authorization': "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOnsiaWQiOjEwMDAwLCJ1c2VyTmFtZSI6ImFkbWluIiwiZGVwdElkIjoxLCJzdGF0aW9uSWQiOjAsImF2YXRhciI6Ii9qZ2ZpbGUvLzIwMjQvNS8yNy8yNzQzMjkzOTU4Mzg4NTIuanBnIiwib3JnSWQiOjF9LCJkZXZpY2UiOiJiYWNrIiwiZWZmIjoxNzIzOTQ2NTQwNzQxLCJyblN0ciI6InpkOWpKZFlBdVpnR0NEd2xBWnZIcXpkUThBaW9xaUh6In0.8fEZh6HCbkE0kmwF6Ru-1JtVSfQN39mB51pIsI6bzDI"
+          //     },
+          //   }).then((res: http.HttpResponse) => {
+          //     this.dialogController.close()
+          //     let model: FileResponseModel = res.result as FileResponseModel
+          //
+          //     // let data: FileModel = JSON.parse(model.data)
+          //
+          //     console.log(TAG, "ddddddd success", JSON.stringify(model));
+          //
+          //     // let data: ESObject = res.result as ESObject
+          //     // // this.netImageUrl = data.data.fileUrl ?? ""
+          //     // console.error("ddddddd    图片地址:  ", `http://10.88.11.201:9000/${data.data.fileUrl}`);
+          //   }).catch((err: BusinessError) => {
+          //     this.dialogController.close()
+          //     console.error(TAG, "ddddddd    fail");
+          //   })
+          // }
+          // catch (e) {
+          //   this.dialogController.close()
+          //   console.log(TAG, 'mk-logger', 'photoPlugin-str', JSON.stringify(e))
+          // }
 
 
           // this.uploadImg3(url)
           // this.uploadImg2(url)
         })
+
+
       }
     });
   }
@@ -219,7 +237,7 @@ struct Index {
         // Web({ src: $rawfile('download.html'), controller: this.controller })//测试下载proxy互相传值
         // Web({ src: $rawfile('local.html'), controller: this.controller }) //测试webview里面选择文件
         // Web({ src: $rawfile('camera.html'), controller: this.controller })//测试相机
-        Web({ src: $rawfile('doc.html'), controller: this.controller })//测试官方文档
+        Web({ src: $rawfile('doc_old.html'), controller: this.controller })//测试官方文档
 
           // Web({
           //   src: 'http://10.88.20.88:3005/login',
@@ -233,8 +251,6 @@ struct Index {
           .domStorageAccess(true)
           .onShowFileSelector((event) => {
             console.log(TAG, "onShowFileSelector", JSON.stringify(event))
-
-
             this.openGallery()
             // setTimeout(() => {
             //   // 这个会触发addEventListener('change')的事件,但是每次的值都要不同。
@@ -247,6 +263,12 @@ struct Index {
               this.registerJS()
             }
           })
+
+          .onPermissionRequest((event) => {
+            console.log(TAG, "onPermissionRequest")
+
+            // event.request.grant([""])
+          })
         // .onConsole((e) => {
         //   console.log(TAG, "onConsole", JSON.stringify(e))
         //   return true

+ 31 - 179
entry/src/main/ets/pages/TooSimplePage.ets

@@ -1,193 +1,45 @@
-import picker from '@ohos.file.picker';
-import common from '@ohos.app.ability.common';
-import fs from '@ohos.file.fs';
-import request from '@ohos.request';
-import { BusinessError } from '@ohos.base';
-
-import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
-import bundleManager from '@ohos.bundle.bundleManager';
-
-import axios, { AxiosError, AxiosProgressEvent, AxiosResponse, FormData, InternalAxiosRequestConfig } from '@ohos/axios'
-import JGRequest from '../utils/Request';
-
-// 获取应用文件路径
-let context = getContext(this) as common.UIAbilityContext;
-let cacheDir = context.cacheDir;
-const logTag = "uploadLog"
-
-// 上传任务配置项
-
-
-// interface UploadConfig {
-//   url?: string,
-//   header?: ESObject,
-//   method?: string,
-//   files?: ESObject,
-//   data?: []
-// }
-
-// let uploadConfig: Upl = {
-//   url: 'http://192.168.3.48:8740/file/upload',
-//   header: { key1: 'Content-Type', key2: 'multipart/form-data' } as ESObject,
-//   method: 'POST',
-//   files: [
-//     { filename: 'test.jpg', name: 'test', uri: 'internal://cache/test.jpg', type: 'jpg' }
-//   ],
-//   data: [
-//     { name: 'fileId', value: 'FP000008' }
-//   ]
-// }
+// xxx.ets
+import web_webview from '@ohos.web.webview';
+import abilityAccessCtrl, { PermissionRequestResult, Permissions } from '@ohos.abilityAccessCtrl';
 
 @Entry
 @Component
-struct Index {
-  @State message: string = ''
-  @State imgSrc: string = ''
+struct WebComponent {
+  controller: web_webview.WebviewController = new web_webview.WebviewController()
 
-  private async openGallery() {
-    let context = getContext(this) as common.UIAbilityContext;
+  aboutToAppear() {
+    // 配置Web开启调试模式
+    web_webview.WebviewController.setWebDebuggingAccess(true);
     let atManager = abilityAccessCtrl.createAtManager();
-    let info = await bundleManager.getBundleInfoForSelf(0);
-    if (info && info.appInfo) {
-      let result = atManager.verifyAccessTokenSync(info.appInfo.accessTokenId, "ohos.permission.READ_MEDIA");
-      if (abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED == result) {
-        console.log("has permission")
-      }
-    } else {
-      atManager.requestPermissionsFromUser(context, ["ohos.permission.READ_MEDIA"], (error, result) => {
-        if (result) {
-          console.log("result: " + JSON.stringify(result));
-          if (result.authResults[0] == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
-            // 用户授予权限
-            this.selectImage();
-          } else {
-            // 用户拒绝权限
-            console.log("permission denied")
+    atManager.requestPermissionsFromUser(getContext(this), ['ohos.permission.CAMERA', 'ohos.permission.MICROPHONE'])
+      .then(data => {
+        let result: Array<number> = data.authResults;
+        let hasPermissions1 = true;
+        result.forEach(item => {
+          if (item === -1) {
+            hasPermissions1 = false;
           }
+        })
+        if (hasPermissions1) {
+          console.info("hasPermissions1")
         } else {
+          console.info(" not hasPermissions1")
         }
-      });
-    }
-  }
-
-  async selectImage() {
-    try {
-      let PhotoSelectOptions = new picker.PhotoSelectOptions();
-      PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;
-      PhotoSelectOptions.maxSelectNumber = 1;
-      let photoPicker = new picker.PhotoViewPicker();
-      photoPicker.select(PhotoSelectOptions).then((PhotoSelectResult) => {
-        console.info('xx PhotoViewPicker.select successfully, PhotoSelectResult uri: ' + JSON.stringify(PhotoSelectResult));
-        // 从图库选择图片后,返回图片uri
-        let uri = PhotoSelectResult.photoUris[0];
-        console.info('xx uri:' + uri)
-        this.imgSrc = uri
-        // 读取上面返回uri
-        let file = fs.openSync(uri, fs.OpenMode.CREATE);
-        // 复制文件到缓存目录下
-        fs.copyFileSync(file.fd, cacheDir + '/test.jpg')
-        // 上传文件到服务器上
-        this.uploadImage()
-      }).catch((err: BusinessError) => {
-        console.error('xx PhotoViewPicker.select failed with err: ' + err);
-      });
-    } catch (err) {
-      console.error('xx PhotoViewPicker failed with err: ' + err);
-    }
-  }
-
-  uploadImage() {
-
-    // let formData = new FormData();
-    // formData.append('file', `internal://cache/test.jpg`);
-    // formData.append('fileName', "test");
-    //
-    //
-    // JGRequest.post<string, AxiosResponse<string>, FormData>("api/v1/base/upload", formData, {
-    //   headers: {
-    //     'Content-Type': 'multipart/form-data',
-    //     'Authorization': "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOnsiaWQiOjEwMDAwLCJ1c2VyTmFtZSI6ImFkbWluIiwiZGVwdElkIjoxLCJzdGF0aW9uSWQiOjAsImF2YXRhciI6Ii9qZ2ZpbGUvLzIwMjQvNS8yNy8yNzQzMjkzOTU4Mzg4NTIuanBnIiwib3JnSWQiOjF9LCJkZXZpY2UiOiJiYWNrIiwiZWZmIjoxNzIzOTQ2NTQwNzQxLCJyblN0ciI6InpkOWpKZFlBdVpnR0NEd2xBWnZIcXpkUThBaW9xaUh6In0.8fEZh6HCbkE0kmwF6Ru-1JtVSfQN39mB51pIsI6bzDI"
-    //   },
-    //   context: getContext(this),
-    //   onUploadProgress: (progressEvent: AxiosProgressEvent): void => {
-    //     console.info(logTag, progressEvent && progressEvent.loaded && progressEvent.total ? Math.ceil(progressEvent.loaded / progressEvent.total * 100) + '%' : '0%');
-    //   },
-    // }).then((res: AxiosResponse) => {
-    //   interface pathType {
-    //     filePath: string
-    //   }
-    //
-    //   interface dataType {
-    //     data: pathType
-    //   }
-    //
-    //   const data: dataType = res.data as dataType
-    //   const path = data.data.filePath
-    //   console.info(logTag, "request result", path);
-    // }).catch((error: AxiosError) => {
-    //   console.error(logTag, "11111error:" + JSON.stringify(error));
-    // })
-    //
-    // return
-
-
-    // 将本地应用文件上传至网络服务器
-    try {
-      request.uploadFile(context, {
-        url: 'http://10.88.11.200:8078/api/v1/base/upload',
-        header: {
-          'Content-Type': 'multipart/form-data',
-          'Authorization': "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOnsiaWQiOjEwMDAwLCJ1c2VyTmFtZSI6ImFkbWluIiwiZGVwdElkIjoxLCJzdGF0aW9uSWQiOjAsImF2YXRhciI6Ii9qZ2ZpbGUvLzIwMjQvNS8yNy8yNzQzMjkzOTU4Mzg4NTIuanBnIiwib3JnSWQiOjF9LCJkZXZpY2UiOiJiYWNrIiwiZWZmIjoxNzIzOTQ2NTQwNzQxLCJyblN0ciI6InpkOWpKZFlBdVpnR0NEd2xBWnZIcXpkUThBaW9xaUh6In0.8fEZh6HCbkE0kmwF6Ru-1JtVSfQN39mB51pIsI6bzDI"
-        },
-        method: 'POST',
-        files: [
-          { filename: 'test.jpg', name: 'test', uri: 'internal://cache/test.jpg', type: 'jpg' }
-        ],
-        data: [
-          { name: 'fileId', value: 'FP000008' }
-        ]
-      })
-        .then((uploadTask) => {
-          uploadTask.on('complete', (taskStates) => {
-            for (let i = 0; i < taskStates.length; i++) {
-              console.info(logTag, `xx upload complete taskState: ${JSON.stringify(taskStates[i])}`);
-              this.message = JSON.stringify(taskStates[i])
-            }
-          });
-          uploadTask.on('progress', (uploadedSize: number, totalSize: number) => {
-            console.info(logTag, `progress: ${totalSize} --- ${uploadedSize}`);
-          })
-          uploadTask.on('fail', (taskStates) => {
-            for (let i = 0; i < taskStates.length; i++) {
-              console.info(logTag, `fail: ${JSON.stringify(taskStates[i])}`);
-              this.message = JSON.stringify(taskStates[i])
-            }
-          });
-
-        })
-        .catch((err: BusinessError) => {
-          console.error(logTag, `failed, code is ${err.code}, message is ${err.message}`);
-          this.message = err.message
-        })
-    } catch (err) {
-      console.error(logTag, ` ERROR, code is ${err.code}, message is ${err.message}`);
-      this.message = err.message
-    }
+      }).catch(() => {
+      return;
+    });
   }
 
   build() {
-    Column({ space: 30 }) {
-      Button('打开图库')
-        .width('80%').height('40')
-        .onClick(() => {
-          this.openGallery()
+    Column() {
+      Web({ src: $rawfile('camera.html'), controller: this.controller })
+        .onPermissionRequest((event) => {
+          if (event) {
+            console.log("openHarmonyBridge", "onPermissionRequest")
+            event.request.grant(event.request.getAccessibleResource())
+          }
+          return true
         })
-      Image(this.imgSrc)
-        .width('50%').height('50%')
-      Text(this.message)
-        .fontSize(20).width('100%')
     }
-    .width('100%').height('100%')
-    .padding(10)
   }
-}
+}

+ 98 - 0
entry/src/main/ets/utils/DateTimeUtil.ts

@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2022 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file 日期工具
+ */
+export default class DateTimeUtil {
+
+  /**
+ * 时分秒
+ */
+  getTime() {
+    const DATETIME = new Date()
+    return this.concatTime(DATETIME.getHours(), DATETIME.getMinutes(), DATETIME.getSeconds())
+  }
+  getHour() {
+    const DATETIME = new Date()
+    return DATETIME.getHours()
+  }
+  getMinute() {
+    const DATETIME = new Date()
+    return DATETIME.getMinutes()
+  }
+  getSecond() {
+    const DATETIME = new Date()
+    return DATETIME.getSeconds()
+  }
+
+  /**
+ * 年月日
+ */
+  getDate() {
+    const DATETIME = new Date()
+    return this.concatDate(DATETIME.getFullYear(), DATETIME.getMonth() + 1, DATETIME.getDate())
+  }
+  getFullYear() {
+    const DATETIME = new Date()
+    return DATETIME.getFullYear()
+  }
+  getMonth() {
+    const DATETIME = new Date()
+    return DATETIME.getMonth() + 1
+  }
+  getDay() {
+    const DATETIME = new Date()
+    return DATETIME.getDate()
+  }
+
+  /**
+ * 日期不足两位补充0
+ * @param value-数据值
+ */
+  fill(value: number) {
+    return (value > 9 ? '' : '0') + value
+  }
+
+  /**
+ * 年月日格式修饰
+ * @param year
+ * @param month
+ * @param date
+ */
+  concatDate(year: number, month: number, date: number) {
+    return `${year}${this.fill(month)}${this.fill(date)}`
+  }
+
+  /**
+ * 时分秒格式修饰
+ * @param hours
+ * @param minutes
+ * @param seconds
+ */
+  concatTime(hours: number, minutes: number, seconds: number) {
+    return `${this.fill(hours)}${this.fill(minutes)}${this.fill(seconds)}`
+  }
+
+  getDurationString(duration: number) {
+    let hour = Math.floor(duration / (1000 * 60 * 60))
+    let minute = Math.floor((duration - hour * (1000 * 60 * 60)) / (1000 * 60))
+    let second = Math.floor((duration - hour * (1000 * 60 * 60) - minute * (60 * 1000)) / 1000)
+    if (hour > 0) {
+      return `${this.fill(hour)}:${this.fill(minute)}:${this.fill(second)}`
+    }
+    return `${this.fill(minute)}:${this.fill(second)}`
+  }
+}

+ 20 - 0
entry/src/main/ets/utils/GlobalThis.ts

@@ -0,0 +1,20 @@
+export class GlobalContext {
+  private constructor() {}
+  private static instance: GlobalContext;
+  private _objects = new Map<string, Object>();
+
+  public static getContext(): GlobalContext {
+    if (!GlobalContext.instance) {
+      GlobalContext.instance = new GlobalContext();
+    }
+    return GlobalContext.instance;
+  }
+
+  getObject(value: string): Object | undefined {
+    return this._objects.get(value);
+  }
+
+  setObject(key: string, objectClass: Object): void {
+    this._objects.set(key, objectClass);
+  }
+}

+ 82 - 0
entry/src/main/ets/utils/UploadUtil.ets

@@ -0,0 +1,82 @@
+import { BusinessError } from '@ohos.base'
+import http from '@ohos.net.http'
+import { FormData, File, FileUpload } from "@ohos/commons-fileupload"
+import fs from '@ohos.file.fs';
+import { ProgressDialog } from '../components/ProgressDialog';
+
+const TAG = "openHarmonyBridge upload"
+
+
+class UploadUtil {
+  private uploadUrl: string = "http://10.88.11.200:8078"
+
+  private constructor() {
+  }
+
+  public token: string = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOnsiaWQiOjEwMDAwLCJ1c2VyTmFtZSI6ImFkbWluIiwiZGVwdElkIjoxLCJzdGF0aW9uSWQiOjAsImF2YXRhciI6Ii9qZ2ZpbGUvLzIwMjQvNS8yNy8yNzQzMjkzOTU4Mzg4NTIuanBnIiwib3JnSWQiOjF9LCJkZXZpY2UiOiJiYWNrIiwiZWZmIjoxNzI0MTIyNTQwMTQwLCJyblN0ciI6IkRkakc3akFSNEtkZ1h5VWV5emhROFVib1ZlOTJUVVo4In0.yVzW8YkjiqLf9T4oUsJUPUifqPFANWX78pov8aGRsFQ"
+  private static instance: UploadUtil;
+
+  public static getInstance(): UploadUtil {
+    if (!UploadUtil.instance) {
+      UploadUtil.instance = new UploadUtil();
+    }
+    return UploadUtil.instance;
+  }
+
+  startUpload(uri: string, callBack: () => void) {
+    //   开始上传
+    try {
+      // 2.2 根据uri同步打开文件
+      const file = fs.openSync(uri)
+      // 2.3 同步获取文件的详细信息
+      const stat = fs.statSync(file.fd)
+      // 2.4 创建缓冲区存储读取的文件流
+      const buffer = new ArrayBuffer(stat.size)
+      // 2.5 开始同步读取文件流到缓冲区
+      fs.readSync(file.fd, buffer)
+      // 2.6 关闭文件流
+      fs.closeSync(file)
+
+      // 3. 转成base64编码的字符串
+      // const helper = new util.Base64Helper()
+      // const str = helper.encodeToStringSync(new Uint8Array(buffer))
+      // console.log('mk-logger', 'photoPlugin-str', buffer.byteLength, JSON.stringify(buffer))
+
+      let toUpFile = new File()
+      toUpFile.fileName = "test.jpg"
+      toUpFile.fileData = buffer
+
+      let fileUpload = new FileUpload({
+        baseUrl: this.uploadUrl,
+        readTimeout: 60000,
+        connectTimeout: 60000,
+      })
+
+      const formData = new FormData();
+      // formData.append("key", 1); //可以添加基本类型的值,目前支持string、number
+      // formData.append("fileName", "test.jpg"); //也可以添加File类型的对象
+      formData.append('file', toUpFile)
+      fileUpload.post("/api/v1/base/upload", formData, {
+        header: {
+          'Content-Type': 'multipart/form-data',
+          'Authorization': this.token,
+        },
+      }).then((res: http.HttpResponse) => {
+        callBack()
+        console.log(TAG, "ddddddd success", JSON.stringify(res.result));
+        //上传完成后浏览器可以产看的图片地址  http://10.88.11.201:9000
+      }).catch((err: BusinessError) => {
+        callBack()
+        console.error(TAG, "ddddddd    fail", JSON.stringify(err));
+      })
+    }
+    catch (e) {
+      callBack()
+      console.log(TAG, 'mk-logger', 'photoPlugin-str', JSON.stringify(e))
+    }
+  }
+}
+
+let uploadInstance = UploadUtil.getInstance();
+
+export default uploadInstance;

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 3 - 0
entry/src/main/resources/base/media/back_white.svg


+ 7 - 0
entry/src/main/resources/base/media/ic_circled.svg

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="76px" height="76px" viewBox="0 0 76 76" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>ic_circled</title>
+    <g id="ic_circled" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <path d="M38,76 C17.0131795,76 0,58.9868205 0,38 C0,17.0131795 17.0131795,0 38,0 C58.9868205,0 76,17.0131795 76,38 C76,58.9868205 58.9868205,76 38,76 Z M38,75 C58.4345357,75 75,58.4345357 75,38 C75,17.5654643 58.4345357,1 38,1 C17.5654643,1 1,17.5654643 1,38 C1,58.4345357 17.5654643,75 38,75 Z" id="Oval" fill="#000000" fill-rule="nonzero"></path>
+    </g>
+</svg>

+ 7 - 0
entry/src/main/resources/base/media/ic_circled_filled.svg

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="54px" height="54px" viewBox="0 0 54 54" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>ic_circled_filled</title>
+    <g id="ic_circled_filled" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <circle id="Path" fill="#000000" cx="27" cy="27" r="27"></circle>
+    </g>
+</svg>

+ 10 - 0
entry/src/main/resources/base/media/take_video_normal.svg

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg viewBox="0 0 76 76" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 63.1 (92452) - https://sketch.com -->
+    <title>ic/camera/shutter/take_video_normal</title>
+    <desc>Created with Sketch.</desc>
+    <g id="ic/camera/shutter/take_video_normal" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <path d="M38,0 C58.9868205,0 76,17.0131795 76,38 C76,58.9868205 58.9868205,76 38,76 C17.0131795,76 0,58.9868205 0,38 C0,17.0131795 17.0131795,0 38,0 Z M38,1 C17.5654643,1 1,17.5654643 1,38 C1,58.4345357 17.5654643,75 38,75 C58.4345357,75 75,58.4345357 75,38 C75,17.5654643 58.4345357,1 38,1 Z M38,11 C52.9116882,11 65,23.0883118 65,38 C65,52.9116882 52.9116882,65 38,65 C23.0883118,65 11,52.9116882 11,38 C11,23.0883118 23.0883118,11 38,11 Z" id="Combined-Shape" fill="#FFFFFF"></path>
+        <circle id="Oval-4-Copy-2" fill="#FF0000" cx="38" cy="38" r="9"></circle>
+    </g>
+</svg>

+ 10 - 0
entry/src/main/resources/base/media/take_video_stop.svg

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg viewBox="0 0 76 76" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 63.1 (92452) - https://sketch.com -->
+    <title>ic/camera/shutter/take_video_stop</title>
+    <desc>Created with Sketch.</desc>
+    <g id="ic/camera/shutter/take_video_stop" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <rect id="Rectangle-11" fill="#FFFFFF" x="27" y="27" width="22" height="22" rx="2"></rect>
+        <path d="M38,76 C17.0131795,76 0,58.9868205 0,38 C0,17.0131795 17.0131795,0 38,0 C58.9868205,0 76,17.0131795 76,38 C76,58.9868205 58.9868205,76 38,76 Z M38,75 C58.4345357,75 75,58.4345357 75,38 C75,17.5654643 58.4345357,1 38,1 C17.5654643,1 1,17.5654643 1,38 C1,58.4345357 17.5654643,75 38,75 Z" id="Oval" fill="#FFFFFF" fill-rule="nonzero"></path>
+    </g>
+</svg>

+ 1 - 1
entry/src/main/resources/base/profile/main_pages.json

@@ -4,6 +4,6 @@
     "pages/WebTestPage",
     "pages/SelectAlbumPage",
     "pages/TooSimplePage",
-    "pages/Base64Page"
+    "pages/CameraPage"
   ]
 }

+ 1 - 6
entry/src/main/resources/rawfile/camera.html

@@ -5,9 +5,8 @@
     <meta charset="UTF-8">
 </head>
 <body>
-<video id="video" width="500px" height="500px" style="border: 1px solid red" autoplay="autoplay"></video>
+<video id="video" width="500px" height="500px" autoplay="autoplay"></video>
 <canvas id="canvas" width="500px" height="500px"></canvas>
-<p id="content">fffff</p>
 <br>
 <input type="button" title="HTML5摄像头" value="开启摄像头" onclick="getMedia()"/>
 <script>
@@ -23,15 +22,11 @@
     let promise = navigator.mediaDevices.getUserMedia(constraints);
     // then()异步,调用MediaStream对象作为参数
     promise.then(function (MediaStream) {
-       document.getElementById("content").innerHtml = JSON.stringfy(MediaStream)
       video.srcObject = MediaStream;
       video.play();
     });
   }
 
-
-
-
 </script>
 </body>
 </html>

+ 13 - 1
entry/src/main/resources/rawfile/doc.html

@@ -8,7 +8,8 @@
 <body>
 <input type="file" id="fileInput" onchange="displayFileName()">
 <div id="fileNameDisplay"></div>
-<button onclick="invokeJS()">调用原生的方法</button>
+<button onclick="invokeJS()">调用download</button>
+<button onclick="invokeCamera()">调用相机</button>
 <button onclick="selectFile()">Select File</button>
 <div id="fileDisplay"></div>
 
@@ -30,6 +31,14 @@
             }));
         }
 
+        function invokeCamera() {
+           let promise = navigator.mediaDevices.getUserMedia(constraints);
+            // then()异步,调用MediaStream对象作为参数
+            promise.then(function (MediaStream) {
+
+            });
+        }
+
         function selectFile() {
             const fileInput = document.getElementById('fileInput');
             fileInput.click();
@@ -58,6 +67,9 @@
 
 
 
+
+
+
 </script>
 </body>
 </html>

+ 63 - 0
entry/src/main/resources/rawfile/doc_old.html

@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>File Input Example</title>
+</head>
+<body>
+<input type="file" id="fileInput" onchange="displayFileName()">
+<div id="fileNameDisplay"></div>
+<button onclick="invokeJS()">调用原生的方法</button>
+<button onclick="invokeCamera()">调用相机</button>
+<button onclick="selectFile()">Select File</button>
+<div id="fileDisplay"></div>
+
+<script>
+        function displayFileName() {
+            const fileInput = document.getElementById('fileInput');
+            const fileNameDisplay = document.getElementById('fileNameDisplay');
+            if (fileInput.files.length > 0) {
+                fileNameDisplay.textContent = fileInput.files[0].name;
+            } else {
+                fileNameDisplay.textContent = '';
+            }
+        }
+
+        function invokeJS() {
+           openHarmonyBridge.download(JSON.stringify({
+              token: "download",
+              path: "调用原生的方法"
+            }));
+        }
+
+        function invokeCamera() {
+
+            openHarmonyBridge.startCamera(JSON.stringify({
+              token: "startCamera",
+              path: "调用相机"
+            }));
+        }
+
+        function selectFile() {
+            openHarmonyBridge.selectFile(JSON.stringify({
+              token: "selectFile",
+              path: "选择文件"
+            }));
+        }
+
+
+
+
+
+
+
+
+
+
+
+
+
+</script>
+</body>
+</html>