锁定移动图片权限请求失败边界

移动文件桥接把相册权限请求失败转为结构化 host_error

移动文件桥接把相机权限请求失败转为结构化 host_error

移动文件单测覆盖权限请求失败不启动原生选择器

移动壳配置检查反查权限请求失败边界
This commit is contained in:
2026-06-20 11:58:28 +08:00
parent 306df618bd
commit d8ef351c59
3 changed files with 43 additions and 2 deletions
@@ -2079,9 +2079,14 @@ for (const snippet of [
"code: 'unsupported_capability'",
"code: 'cancelled'",
'rejects image import before picker launch when library permission is denied',
'rejects image import before picker launch when library permission request fails',
'rejects image capture before camera launch when camera permission request fails',
"message: 'photo library permission denied'",
"message: 'photo library permission unavailable'",
'expect(imageLibraryMock).not.toHaveBeenCalled()',
"message: 'camera permission denied'",
"message: 'camera permission unavailable'",
'expect(cameraMock).not.toHaveBeenCalled()',
"mediaTypes: ['images']",
"options: { encoding: 'base64' }",
]) {
@@ -303,6 +303,26 @@ describe('mobile HostBridge file actions', () => {
expect(imageLibraryMock).not.toHaveBeenCalled();
});
test('rejects image import before picker launch when library permission request fails', async () => {
libraryPermissionMock.mockRejectedValueOnce(new Error('native permission failed'));
await expect(importImageFile()).rejects.toMatchObject({
code: 'host_error',
message: 'photo library permission unavailable',
});
expect(imageLibraryMock).not.toHaveBeenCalled();
});
test('rejects image capture before camera launch when camera permission request fails', async () => {
cameraPermissionMock.mockRejectedValueOnce(new Error('native permission failed'));
await expect(captureImageFile()).rejects.toMatchObject({
code: 'host_error',
message: 'camera permission unavailable',
});
expect(cameraMock).not.toHaveBeenCalled();
});
test('imports audio and exports binary files through controlled payloads', async () => {
fileBase64Data.set('file:///picked/voice.mp3', MP3_BASE64);
fileSizes.set('file:///picked/voice.mp3', Buffer.byteLength('ID3\x04\x00\x00\x00\x00\x00\x10'));
+18 -2
View File
@@ -270,7 +270,15 @@ export async function exportMobileHostBridgeImageFile(
}
export async function importImageFile(): Promise<FileImportImageResult> {
const permission = await ImagePicker.requestMediaLibraryPermissionsAsync();
let permission: ImagePicker.MediaLibraryPermissionResponse;
try {
permission = await ImagePicker.requestMediaLibraryPermissionsAsync();
} catch {
throw {
code: 'host_error',
message: 'photo library permission unavailable',
} satisfies HostBridgeError;
}
if (permission.status !== ImagePicker.PermissionStatus.GRANTED) {
throw {
code: 'host_error',
@@ -301,7 +309,15 @@ export async function importMobileHostBridgeImageFile(
}
export async function captureImageFile(): Promise<FileImportImageResult> {
const permission = await ImagePicker.requestCameraPermissionsAsync();
let permission: ImagePicker.CameraPermissionResponse;
try {
permission = await ImagePicker.requestCameraPermissionsAsync();
} catch {
throw {
code: 'host_error',
message: 'camera permission unavailable',
} satisfies HostBridgeError;
}
if (permission.status !== ImagePicker.PermissionStatus.GRANTED) {
throw {
code: 'host_error',