Use add-only photo permission when saving QR codes (#10854)

This commit is contained in:
Spence Pope
2026-06-10 16:39:40 -04:00
committed by GitHub
parent 156903070b
commit b667cafca1
2 changed files with 12 additions and 6 deletions
+7 -4
View File
@@ -1,8 +1,7 @@
import {Suspense, useRef, useState} from 'react'
import {View} from 'react-native'
import type ViewShot from 'react-native-view-shot'
import {requestMediaLibraryPermissionsAsync} from 'expo-image-picker'
import {createAssetAsync} from 'expo-media-library'
import {requestPermissionsAsync, saveToLibraryAsync} from 'expo-media-library'
import * as Sharing from 'expo-sharing'
import {type AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api'
import {msg} from '@lingui/core/macro'
@@ -60,7 +59,9 @@ export function QrCodeDialog({
const onSavePress = async () => {
ref.current?.capture?.().then(async (uri: string) => {
if (IS_NATIVE) {
const res = await requestMediaLibraryPermissionsAsync()
// Write-only permission - saving the QR image does not require read
// access to the user's photo library.
const res = await requestPermissionsAsync(true)
if (!res.granted) {
Toast.show(
@@ -73,7 +74,9 @@ export function QrCodeDialog({
// Incase of a FS failure, don't crash the app
try {
await createAssetAsync(`file://${uri}`)
// saveToLibraryAsync writes without reading the asset back, so it
// works with the add-only permission on iOS (APP-2374)
await saveToLibraryAsync(`file://${uri}`)
} catch (e: unknown) {
Toast.show(_(msg`An error occurred while saving the QR code!`), {
type: 'error',
@@ -2,7 +2,7 @@ import {Suspense, useRef, useState} from 'react'
import {Pressable, View} from 'react-native'
import type ViewShot from 'react-native-view-shot'
import {setStringAsync} from 'expo-clipboard'
import {createAssetAsync, requestPermissionsAsync} from 'expo-media-library'
import {requestPermissionsAsync, saveToLibraryAsync} from 'expo-media-library'
import {useLingui} from '@lingui/react/macro'
import {useNavigation} from '@react-navigation/native'
@@ -92,7 +92,10 @@ export function InviteFriendsDialogInner({
}
try {
await createAssetAsync(`file://${uri}`)
// saveToLibraryAsync writes without reading the asset back, so it works
// with the add-only permission. createAssetAsync fetches the created
// asset, which triggers the full library read prompt on iOS (APP-2374).
await saveToLibraryAsync(`file://${uri}`)
ax.metric('invite:action:download', {})
Toast.show(l`QR code saved to your camera roll!`)
} catch (err) {