1# 相机启动恢复实现方案(ArkTS)
2
3当前示例提供完整的相机应用从后台切换至前台启动恢复的流程介绍,方便开发者了解完整的接口调用顺序。
4
5相机应用在前后台切换过程中的状态变化说明:
6- 当相机应用在退后台之后由于安全策略会被强制断流,并且此时相机状态回调会返回相机可用状态,表示当前相机设备已经被关闭,处于空闲状态。
7- 当相机应用从后台切换至前台时,相机状态回调会返回相机不可用状态,表示当前相机设备被打开,处于忙碌状态。
8- 相机应用从后台切换至前台时,需要重启相机设备的预览流、拍照流以及相机会话管理。
9
10在参考以下示例前,建议开发者建议开发者查看[相机开发指导(ArkTS)](camera-preparation.md)的具体章节,了解[相机管理](camera-device-management.md)、[设备输入](camera-device-input.md)、[会话管理](camera-session-management.md)等单个操作。
11
12
13## 开发流程
14
15相机应用从后台切换至前台启动恢复调用流程图建议如下:
16
17![Camera Background recovery processing](figures/camera-background-recovery.png)
18
19## 完整示例
20
21Context获取方式请参考:[获取UIAbility的上下文信息](../../application-models/uiability-usage.md#获取uiability的上下文信息)。
22
23相机应用从后台切换至前台启动恢复需要在页面生命周期回调函数onPageShow中调用,重新初始化相机设备。
24
25   ```ts
26   import { camera } from '@kit.CameraKit';
27   import { BusinessError } from '@kit.BasicServicesKit';
28   import { common } from '@kit.AbilityKit';
29
30   let context: common.BaseContext;
31   let surfaceId: string = '';
32   async function onPageShow(): Promise<void> {
33      // 当应用从后台切换至前台页面显示时,重新初始化相机设备
34      await initCamera(context, surfaceId);
35   }
36
37   async function initCamera(baseContext: common.BaseContext, surfaceId: string): Promise<void> {
38      console.info('onForeGround recovery begin.');
39      let cameraManager: camera.CameraManager = camera.getCameraManager(context);
40      if (!cameraManager) {
41        console.error("camera.getCameraManager error");
42        return;
43      }
44      // 监听相机状态变化
45      cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => {
46          if (err !== undefined && err.code !== 0) {
47            console.error('cameraStatus with errorCode = ' + err.code);
48            return;
49          }
50          console.info(`camera : ${cameraStatusInfo.camera.cameraId}`);
51          console.info(`status: ${cameraStatusInfo.status}`);
52        });
53
54      // 获取相机列表
55      let cameraArray: Array<camera.CameraDevice> = cameraManager.getSupportedCameras();
56      if (cameraArray.length <= 0) {
57        console.error("cameraManager.getSupportedCameras error");
58        return;
59      }
60
61      for (let index = 0; index < cameraArray.length; index++) {
62        console.info('cameraId : ' + cameraArray[index].cameraId);                       // 获取相机ID
63        console.info('cameraPosition : ' + cameraArray[index].cameraPosition);           // 获取相机位置
64        console.info('cameraType : ' + cameraArray[index].cameraType);                   // 获取相机类型
65        console.info('connectionType : ' + cameraArray[index].connectionType);           // 获取相机连接类型
66      }
67
68      // 创建相机输入流
69      let cameraInput: camera.CameraInput | undefined = undefined;
70      try {
71        cameraInput = cameraManager.createCameraInput(cameraArray[0]);
72      } catch (error) {
73          let err = error as BusinessError;
74          console.error('Failed to createCameraInput errorCode = ' + err.code);
75      }
76      if (cameraInput === undefined) {
77        return;
78      }
79
80      // 监听cameraInput错误信息
81      let cameraDevice: camera.CameraDevice = cameraArray[0];
82        cameraInput.on('error', cameraDevice, (error: BusinessError) => {
83        console.error(`Camera input error code: ${error.code}`);
84      });
85
86      // 打开相机
87      await cameraInput.open();
88
89      // 获取支持的模式类型
90      let sceneModes: Array<camera.SceneMode> = cameraManager.getSupportedSceneModes(cameraArray[0]);
91      let isSupportPhotoMode: boolean = sceneModes.indexOf(camera.SceneMode.NORMAL_PHOTO) >= 0;
92      if (!isSupportPhotoMode) {
93        console.error('photo mode not support');
94        return;
95      }
96      // 获取相机设备支持的输出流能力
97      let cameraOutputCap: camera.CameraOutputCapability = cameraManager.getSupportedOutputCapability(cameraArray[0], camera.SceneMode.NORMAL_PHOTO);
98      if (!cameraOutputCap) {
99        console.error("cameraManager.getSupportedOutputCapability error");
100        return;
101      }
102      console.info("outputCapability: " + JSON.stringify(cameraOutputCap));
103
104      let previewProfilesArray: Array<camera.Profile> = cameraOutputCap.previewProfiles;
105      if (!previewProfilesArray) {
106        console.error("createOutput previewProfilesArray == null || undefined");
107      }
108
109      let photoProfilesArray: Array<camera.Profile> = cameraOutputCap.photoProfiles;
110      if (!photoProfilesArray) {
111        console.error("createOutput photoProfilesArray == null || undefined");
112      }
113
114      // 创建预览输出流,其中参数 surfaceId 参考上文 XComponent 组件,预览流为XComponent组件提供的surface
115      let previewOutput: camera.PreviewOutput | undefined = undefined;
116      try {
117        previewOutput = cameraManager.createPreviewOutput(previewProfilesArray[0], surfaceId);
118      } catch (error) {
119        let err = error as BusinessError;
120        console.error(`Failed to create the PreviewOutput instance. error code: ${err.code}`);
121      }
122      if (previewOutput === undefined) {
123        return;
124      }
125      // 监听预览输出错误信息
126      previewOutput.on('error', (error: BusinessError) => {
127        console.error(`Preview output error code: ${error.code}`);
128      });
129
130      // 创建拍照输出流
131      let photoOutput: camera.PhotoOutput | undefined = undefined;
132      try {
133        photoOutput = cameraManager.createPhotoOutput(photoProfilesArray[0]);
134      } catch (error) {
135          let err = error as BusinessError;
136          console.error('Failed to createPhotoOutput errorCode = ' + err.code);
137      }
138      if (photoOutput === undefined) {
139        return;
140      }
141
142      //创建会话
143      let photoSession: camera.PhotoSession | undefined = undefined;
144      try {
145        photoSession = cameraManager.createSession(camera.SceneMode.NORMAL_PHOTO) as camera.PhotoSession;
146      } catch (error) {
147          let err = error as BusinessError;
148          console.error('Failed to create the session instance. errorCode = ' + err.code);
149      }
150      if (photoSession === undefined) {
151        return;
152      }
153      // 监听session错误信息
154      photoSession.on('error', (error: BusinessError) => {
155        console.error(`Capture session error code: ${error.code}`);
156      });
157
158      // 开始配置会话
159      try {
160        photoSession.beginConfig();
161      } catch (error) {
162          let err = error as BusinessError;
163          console.error('Failed to beginConfig. errorCode = ' + err.code);
164      }
165
166      // 向会话中添加相机输入流
167      try {
168        photoSession.addInput(cameraInput);
169      } catch (error) {
170          let err = error as BusinessError;
171          console.error('Failed to addInput. errorCode = ' + err.code);
172      }
173
174      // 向会话中添加预览输出流
175      try {
176        photoSession.addOutput(previewOutput);
177      } catch (error) {
178          let err = error as BusinessError;
179          console.error('Failed to addOutput(previewOutput). errorCode = ' + err.code);
180      }
181
182      // 向会话中添加拍照输出流
183      try {
184        photoSession.addOutput(photoOutput);
185      } catch (error) {
186          let err = error as BusinessError;
187          console.error('Failed to addOutput(photoOutput). errorCode = ' + err.code);
188      }
189
190      // 提交会话配置
191      await photoSession.commitConfig();
192
193      // 启动会话
194      await photoSession.start().then(() => {
195        console.info('Promise returned to indicate the session start success.');
196      });
197      // 判断设备是否支持闪光灯
198      let flashStatus: boolean = false;
199        try {
200          flashStatus = photoSession.hasFlash();
201      } catch (error) {
202          let err = error as BusinessError;
203          console.error('Failed to hasFlash. errorCode = ' + err.code);
204      }
205      console.info('Returned with the flash light support status:' + flashStatus);
206
207      if (flashStatus) {
208        // 判断是否支持自动闪光灯模式
209        let flashModeStatus: boolean = false;
210        try {
211          let status: boolean = photoSession.isFlashModeSupported(camera.FlashMode.FLASH_MODE_AUTO);
212          flashModeStatus = status;
213        } catch (error) {
214            let err = error as BusinessError;
215            console.error('Failed to check whether the flash mode is supported. errorCode = ' + err.code);
216        }
217        if(flashModeStatus) {
218          // 设置自动闪光灯模式
219          try {
220            photoSession.setFlashMode(camera.FlashMode.FLASH_MODE_AUTO);
221          } catch (error) {
222              let err = error as BusinessError;
223              console.error('Failed to set the flash mode. errorCode = ' + err.code);
224          }
225        }
226      }
227
228      // 判断是否支持连续自动变焦模式
229      let focusModeStatus: boolean = false;
230      try {
231        let status: boolean = photoSession.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO);
232        focusModeStatus = status;
233      } catch (error) {
234          let err = error as BusinessError;
235          console.error('Failed to check whether the focus mode is supported. errorCode = ' + err.code);
236      }
237
238      if (focusModeStatus) {
239        // 设置连续自动变焦模式
240        try {
241          photoSession.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO);
242        } catch (error) {
243            let err = error as BusinessError;
244            console.error('Failed to set the focus mode. errorCode = ' + err.code);
245        }
246      }
247
248      // 获取相机支持的可变焦距比范围
249      let zoomRatioRange: Array<number> = [];
250      try {
251        zoomRatioRange = photoSession.getZoomRatioRange();
252      } catch (error) {
253          let err = error as BusinessError;
254          console.error('Failed to get the zoom ratio range. errorCode = ' + err.code);
255      }
256      if (zoomRatioRange.length <= 0) {
257        return;
258      }
259      // 设置可变焦距比
260      try {
261        photoSession.setZoomRatio(zoomRatioRange[0]);
262      } catch (error) {
263          let err = error as BusinessError;
264          console.error('Failed to set the zoom ratio value. errorCode = ' + err.code);
265      }
266      let photoCaptureSetting: camera.PhotoCaptureSetting = {
267        quality: camera.QualityLevel.QUALITY_LEVEL_HIGH, // 设置图片质量高
268        rotation: camera.ImageRotation.ROTATION_0 // 设置图片旋转角度0
269      }
270      // 使用当前拍照设置进行拍照
271      photoOutput.capture(photoCaptureSetting, (err: BusinessError) => {
272        if (err) {
273          console.error(`Failed to capture the photo ${err.message}`);
274          return;
275        }
276        console.info('Callback invoked to indicate the photo capture request success.');
277      });
278
279      console.info('onForeGround recovery end.');
280   }
281   ```