无法在 Android 上的 Expo-Go 应用程序上使用 react-native 拍摄和保存屏幕截图

问题描述 投票:0回答:0

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', 
  },
});
react-native expo screenshot camera-roll expo-go
© www.soinside.com 2019 - 2024. All rights reserved.