SDK版本:47.0.9 Android/iOS 上的 Expo-Go
我正在按照 Expo-Go 介绍教程创建一个名为 StickerSmash 的应用程序。这里:https://docs.expo.dev/tutorial/screenshot/#capture-a-screenshot-and-save-it
现在,当我在相机胶卷中找到要编辑的图像并向其添加表情符号,然后按保存按钮时……我会在日志中收到此错误:
“Missing MEDIA_LIBRARY write permission”
我已经使用 chatGPT4 帮助我调试了几天,但我仍然无法弄清楚问题出在哪里。我没有收到“已保存!”的警报(我应该收到)当我点击保存按钮时,屏幕截图没有保存到我的相机胶卷中。
我认为问题出在
requestPermission();
行以及没有向用户提供对话框的事实,在此if语句中:
if (status === null) {
console.log("the status was null");
requestPermission();
// console.log("the status1 %s", status);
}
此外,expo 教程在返回行中存在差异,这可能会导致一些错误。本质上,我的代码是这样的:
<GestureHandlerRootView style={styles.container}>
**<View style={styles.container}>**
<View style={styles.imageContainer}>
<View ref={imageRef} collapsable={false}>
但是世博会文档只有这个:
<GestureHandlerRootView style={styles.container}>
<View style={styles.imageContainer}>
<View ref={imageRef} collapsable={false}>
这是代码:
import * as MediaLibrary from 'expo-media-library';
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View, Image } from 'react-native';
import Button from './components/Button';
import ImageViewer from './components/ImageViewer';
import * as ImagePicker from 'expo-image-picker';
import {useState, useRef} from 'react';
import CircleButton from './components/CircleButton';
import IconButton from './components/IconButton';
import EmojiPicker from "./components/EmojiPicker";
import EmojiList from './components/EmojiList'
import EmojiSticker from './components/EmojiSticker';
import {GestureHandlerRootView} from "react-native-gesture-handler";
import { captureRef } from 'react-native-view-shot';
// import * as Permissions from 'expo-permissions';
const PlaceholderImage = require('./assets/images/background-image.png');
export default function App() {
const imageRef = useRef();
const [status, requestPermission] = MediaLibrary.usePermissions();
const [isModalVisible, setIsModalVisible] = useState(false);
const [showAppOptions, setShowAppOptions] = useState(false);
const [selectedImage, setSelectedImage] = useState(null);
const [pickedEmoji, setPickedEmoji] = useState(null);
// const [status, setStatus] = useState(null);
if (status === null) {
console.log("the status was null");
requestPermission();
// console.log("the status1 %s", status);
}
const onSaveImageAsync = async () => {
try {
// console.log("the status2 %s", status);
const localUri = await captureRef(imageRef, {
height: 440,
quality: 1,
});
// console.log("the status3 %s", status);
await MediaLibrary.saveToLibraryAsync(localUri);
if (localUri) {
// console.log("the status4 %s", status);
alert("Saved!");
}
} catch (e) {
// console.log("the status5 %s", status);
console.log(e);
}
};
const pickImageAsync = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
quality: 1,
});
if (!result.canceled) {
setSelectedImage(result.assets[0].uri);
setShowAppOptions(true);
} else {
alert('You did not select any image.');
}
}
const onReset = () => {
setShowAppOptions(false);
};
const onAddSticker = () => {
setIsModalVisible(true);
};
const onModalClose = () => {
setIsModalVisible(false);
};
return (
<GestureHandlerRootView style={styles.container}>
<View style={styles.container}>
<View style={styles.imageContainer}>
<View ref={imageRef} collapsable={false}>
<ImageViewer placeholderImageSource={PlaceholderImage} selectedImage={selectedImage} />
{pickedEmoji !== null ? (
<EmojiSticker imageSize={40} stickerSource={pickedEmoji} />
) : null}
</View>
</View>
{showAppOptions ? (
<View style = {styles.optionsContainer}>
<View style = {styles.optionsRow}>
<IconButton icon="refresh" label="Reset" onPress={onReset} />
<CircleButton onPress={onAddSticker} />
<IconButton icon="save-alt" label="Save" onPress={onSaveImageAsync} />
</View>
</View>
//{/* <View /> */}
) : (
<View style={styles.footerContainer}>
<Button theme="primary" label="Choose a photo" onPress={pickImageAsync}/>
<Button label="Use this photo" onPress={() => setShowAppOptions(true)}/>
</View>
)}
<EmojiPicker isVisible={isModalVisible} onClose={onModalClose}>
<EmojiList onSelect={setPickedEmoji} onCloseModal={onModalClose}/>
</EmojiPicker>
<StatusBar style="auto" />
</View>
</GestureHandlerRootView>
);
}
const styles = StyleSheet.create({
footerContainer: {
flex: 1 / 3,
alignItems: 'center',
},
container: {
flex: 1,
backgroundColor: '#00008b',
alignItems: 'center',
},
imageContainer: {
flex: 1,
paddingTop: 60,
},
image: {
width: 320,
height: 440,
borderRadius: 18,
},
optionsContainer: {
position: 'absolute',
bottom: 80,
},
optionsRow: {
alignItems: 'center',
flexDirection: 'row',
},
});