react-native + Expo fails with Unhandled promise rejection: TypeError: undefined is not an object (evaluating '_this.camera.takePictureAsync')

react-native + Expo fails with Unhandled promise rejection: TypeError: undefined is not an object (evaluating '_this.camera.takePictureAsync')

我正在使用 react-native v0.63 和 Expo SDK 38 进行开发。我的目标是读取 android 或 ios phone 和 select 图片然后将这些图片故事化成一个数组,显示在手机屏幕上。我通过研究发现 Expo SDK 38 不支持 react-native cameraroll,必须使用 expo-media-library 来实现这些功能。作为测试,我从研究中提取了一些代码,这些代码要求获得访问相机和相机胶卷的权限。没关系。然后我调用 this.camera.takePictureAsync() 看看我是否可以访问相机拍照。简单的测试。那就是我得到错误的地方:未处理的承诺拒绝:TypeError:undefined is not an object (evaluating '_this.camera.takePictureAsync')

这是我的设置: 完整的错误是:

WARNING
18:17
[Unhandled promise rejection: TypeError: undefined is not an object (evaluating '_this.camera.takePictureAsync')]

Stack trace:
  node_modules\react-navigation\node_modules\@react-navigation\native\lib\module\createNavigationAwareScrollable.js:105:6 in NavigationAwareScrollable#render
  node_modules\regenerator-runtime\runtime.js:45:36 in tryCatch
  node_modules\regenerator-runtime\runtime.js:274:29 in invoke
  node_modules\regenerator-runtime\runtime.js:45:36 in tryCatch
  node_modules\regenerator-runtime\runtime.js:135:27 in invoke
  node_modules\regenerator-runtime\runtime.js:170:16 in PromiseImpl$argument_0
  node_modules\promise\setimmediate\core.js:45:6 in tryCallTwo
  node_modules\promise\setimmediate\core.js:200:22 in doResolve
  node_modules\promise\setimmediate\core.js:66:11 in Promise
  node_modules\regenerator-runtime\runtime.js:169:15 in callInvokeWithMethodAndArg
  node_modules\regenerator-runtime\runtime.js:192:38 in enqueue
  node_modules\regenerator-runtime\runtime.js:219:8 in exports.async
  http://192.168.0.27:19001/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&minify=false&hot=false:253923:41 in _callee
  http://192.168.0.27:19001/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&minify=false&hot=false:254521:108 in onPress
  node_modules\react-native\Libraries\Components\Touchable\TouchableNativeFeedback.js:169:10 in Pressability$argument_0.onPress
  node_modules\react-native\Libraries\Pressability\Pressability.js:655:17 in _performTransitionSideEffects
  node_modules\react-native\Libraries\Pressability\Pressability.js:589:6 in _receiveSignal
  node_modules\react-native\Libraries\Pressability\Pressability.js:499:8 in responderEventHandlers.onResponderRelease
  node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:286:4 in invokeGuardedCallbackImpl
  node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:497:2 in invokeGuardedCallback
  node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:521:2 in invokeGuardedCallbackAndCatchFirstError
  node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:683:41 in executeDispatch
  node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:707:19 in executeDispatchesInOrder
  node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:872:28 in executeDispatchesAndRelease
  [native code]:null in forEach
  node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:851:4 in forEachAccumulated
  node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:897:20 in runEventsInBatch
  node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:1069:18 in runExtractedPluginEventsInBatch
  node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:2835:35 in batchedUpdates$argument_0
  node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:20569:13 in batchedUpdates
  node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:2731:29 in batchedUpdates
  node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:2834:16 in _receiveRootNodeIDEvent
  node_modules\react-native\Libraries\Renderer\implementations\ReactNativeRenderer-dev.js:2911:27 in receiveTouches
  node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:425:19 in __callFunction
  node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:112:6 in __guard$argument_0
  node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:373:10 in __guard
  node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:111:4 in callFunctionReturnFlushedQueue
  [native code]:null in callFunctionReturnFlushedQueue
  ...

我的进口商品:

import React, { Component } from "react";
import styles from "./styles";
import {  Platform, Image, ImageBackground, TextInput, TouchableWithoutFeedback, TouchableOpacity, Dimensions, FlatList, SafeAreaView,TouchableHighlight, View as RNView, Text, Alert } from "react-native";
import {Container, Grid, Col, Row, Header, Content, Item, Input, View, List, ListItem, Textarea, Button, Form, Accordion,  Left, Right, Body,Thumbnail, Icon, Title, Spinner, Picker, DatePicker, } from 'native-base';
import { Ionicons } from '@expo/vector-icons';
import { FlatGrid } from 'react-native-super-grid';
import {Image as SVGImage} from "react-native-svg";
import Fire from '../Fire';
import firebase from 'firebase';
import * as ImagePicker from 'expo-image-picker';
// import * as Permissions from 'expo-permissions';
import Expo, { Constants, } from 'expo';
import * as MediaLibrary from 'expo-media-library';
import * as Permissions from 'expo-permissions';
import { Camera } from 'expo-camera';

获取权限我调用:

    async componentDidMount() {
        this.getCameraPermissions();
    }

                    
    async getCameraPermissions() {
        console.log('getCameraPermissions: enter function');

        const { status } = await Permissions.askAsync(Permissions.CAMERA);

        if (status === 'granted') {
            console.log("getCameraPermissions: status = "+status);
                this.setState({ cameraGranted: true });
        } else {
            this.setState({ cameraGranted: false });
            console.log('Uh oh! The user has not granted us permission.');
        }

        this.getCameraRollPermissions();
   }

   async getCameraRollPermissions() {
       console.log("getCameraRollPermissions: Enter Function");

       const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL);

       if (status === 'granted') {
           console.log("getCameraRollPermissions: status = "+status);
           this.setState({ rollGranted: true });
       } else {
         console.log('Uh oh! The user has not granted us permission.');
         this.setState({ rollGranted: false });
       }
   }

这是抛出错误的函数调用。您可以通过控制台日志看到它进入函数并死于 takepictureasync()

takePictureAndCreateAlbum = async () => {
    console.log('takePictureCreateAlbum: Entering function');
    const { uri } = await this.camera.takePictureAsync()
        .then(() => {
             Alert.alert('takePictureCreateAlbum: taking picture')
        })
        .catch(error => {
             Alert.alert('takePictureCreateAlbum Error!');
        });

    console.log('takePictureCreateAlbum: uri', uri);

    const asset = await MediaLibrary.createAssetAsync(uri);
        console.log('asset', asset);
        MediaLibrary.createAlbumAsync('Expo', asset)
            .then(() => {
                 Alert.alert('Album created!')
            })
            .catch(error => {
                 Alert.alert('An Error Occurred!')
            });
        };

作为测试,我通过此处的按钮调用它:

<Button
    style={{flex: 1, justifyContent: "flex-start", backgroundColor: "lightgrey", marginRight: 5}}
    onPress={() => 
        this.state.rollGranted && this.state.cameraGranted
        ? this.takePictureAndCreateAlbum()
        : Alert.alert('Permissions not granted')
        // this.switchToStories();
    }
>

我正在模拟的 android 设备和真实的 android 设备三星 S7 上进行测试。两者都会产生错误。

我以为我可以捕获错误但失败了。我还尝试从调用中返回所有值,而不仅仅是 uri 并且它的行为相同。想法?

好的,我希望这能帮助其他落入这个陷阱的人。这个错误归结为真正理解 .then .catch 错误 handling.I 需要在 .then()

中对 uri 执行任何功能

可以在这里阅读一篇很棒的短文,让我继续前进: https://medium.com/@lucymarmitchell/using-then-catch-finally-to-handle-errors-in-javascript-promises-6de92bce3afc

还有我调用的相机功能错了:

const { uri } = await this.camera.takePictureAsync()
    .then(() => {
         Alert.alert('takePictureCreateAlbum: taking picture')
    })
    .catch(error => {
         Alert.alert('takePictureCreateAlbum Error!');
    });

需要从 this.camera.takePictureAsync() 中删除 this