You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Expo启动App遇TypeError:无法读取null的launchImageLibrary属性

问题:使用npx expo start启动应用时出现TypeError: Cannot read property "launchImageLibrary" of null错误

错误信息

Console Warning : Possible unhandled promise rejection (id:0):
TypeError: Cannot read property "launchImageLibrary" of null

相关代码

UploadScreen.tsx

import React, { useState } from 'react';
import { StyleSheet, View, Text, Button, Image } from 'react-native';
import { launchCamera, launchImageLibrary } from 'react-native-image-picker';
import { StackNavigationProp } from '@react-navigation/stack';
import { YourStackParamList } from '../type';

type HomeScreenProps = {
  navigation: StackNavigationProp<YourStackParamList, 'Home'>;
};

function UploadScreen({ navigation }: HomeScreenProps) {
  const [imageUri, setImageUri] = useState<string | null>(null);

  const openImagePicker = async () => {
    const result = await launchImageLibrary({
      mediaType: 'photo',
      quality: 1,
    });
  
    if (result.assets && result.assets.length > 0 && result.assets[0].uri) {
      setImageUri(result.assets[0].uri);
    } else {
      setImageUri(null);
    }
  };
  
  const openCamera = async () => {
    const result = await launchCamera({
      mediaType: 'photo',
      cameraType: 'back',
      quality: 1,
    });
  
    if (result.assets && result.assets.length > 0 && result.assets[0].uri) {
      setImageUri(result.assets[0].uri);
    } else {
      setImageUri(null); 
    }
  };
  

  return (
    <View style={styles.container}>
      <Text style={styles.text}> Upload</Text>
      <Button title="Sélectionner depuis la galerie" onPress={openImagePicker} />
      <Button title="Prendre une photo" onPress={openCamera} />
      {imageUri && <Image source={{ uri: imageUri }} style={styles.image} />}
    </View>
  );
}

export default UploadScreen;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  text: {
    color: '#0C1947',
    fontSize: 20,
    marginBottom: 20,
  },
  image: {
    width: 300,
    height: 300,
    marginTop: 20,
  },
});

app.json

{
  "expo": {
    "name": "oysterCVApp",
    "slug": "oysterCVApp",
    "version": "1.0.0",
    "orientation": "portrait",
    "icon": "./assets/icon.png",
    "userInterfaceStyle": "light",
    "splash": {
      "image": "./assets/splash.png",
      "resizeMode": "contain",
      "backgroundColor": "#ffffff"
    },
    "assetBundlePatterns": ["**/*"],
    "ios": {
      "supportsTablet": true,
      "infoPlist": {
        "NSCameraUsageDescription": "Cette application a besoin d'accéder à la caméra pour prendre des photos.",
        "NSPhotoLibraryUsageDescription": "Cette application a besoin d'accéder à la bibliothèque de photos pour sélectionner des images.",
        "NSPhotoLibraryAddUsageDescription": "Cette application a besoin d'ajouter des images à la bibliothèque de photos."
      }
    },
    "android": {
      "adaptiveIcon": {
        "foregroundImage": "./assets/adaptive-icon.png",
        "backgroundColor": "#ffffff"
      },
      "permissions": ["CAMERA", "READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE"]
    },
    "web": {
      "favicon": "./assets/favicon.png"
    }
  }
}

package.json

{
  "name": "oystercvapp",
  "version": "1.0.0",
  "scripts": {
    "start": "npx expo start src/App.tsx",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web"
  },
  "dependencies": {
    "@react-navigation/native": "^6.1.9",
    "@react-navigation/native-stack": "^6.9.17",
    "@react-navigation/stack": "^6.3.20",
    "expo": "~50.0.6",
    "expo-permissions": "^14.4.0",
    "expo-status-bar": "~1.11.1",
    "react": "18.2.0",
    "react-native": "0.73.4",
    "react-native-image-picker": "^7.1.0"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0",
    "@types/react": "~18.2.45",
    "@types/react-native": "^0.73.0",
    "typescript": "^5.1.3"
  },
  "private": true
}

复现步骤

  • 使用npx expo start启动应用
  • 导航至上传页面
  • 尝试从图库选择图片或拍照

预期行为

应用应允许用户无错误地从图库选图或拍照

补充说明

已在app.json中配置了访问相机和图库的必要权限,且已确认react-native-image-picker已正确安装并更新至最新版本。


解决方案

问题根源

react-native-image-picker是原生React Native模块,无法在Expo Go环境中直接使用——Expo有专属的图片选择库expo-image-picker,两者API不兼容,导致调用时出现null引用错误。

修复步骤

  1. 替换依赖库
    卸载react-native-image-picker,安装expo-image-picker:

    npm uninstall react-native-image-picker
    npx expo install expo-image-picker
    
  2. 修改UploadScreen.tsx代码
    替换导入并适配expo-image-picker的API:

    import React, { useState } from 'react';
    import { StyleSheet, View, Text, Button, Image } from 'react-native';
    import * as ImagePicker from 'expo-image-picker';
    import { StackNavigationProp } from '@react-navigation/stack';
    import { YourStackParamList } from '../type';
    
    type HomeScreenProps = {
      navigation: StackNavigationProp<YourStackParamList, 'Home'>;
    };
    
    function UploadScreen({ navigation }: HomeScreenProps) {
      const [imageUri, setImageUri] = useState<string | null>(null);
    
      const openImagePicker = async () => {
        // 请求图库权限
        const permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync();
        if (!permissionResult.granted) {
          alert("需要授予图库访问权限");
          return;
        }
    
        const result = await ImagePicker.launchImageLibraryAsync({
          mediaTypes: ImagePicker.MediaTypeOptions.Images,
          quality: 1,
        });
    
        if (!result.canceled && result.assets[0].uri) {
          setImageUri(result.assets[0].uri);
        } else {
          setImageUri(null);
        }
      };
      
      const openCamera = async () => {
        // 请求相机权限
        const permissionResult = await ImagePicker.requestCameraPermissionsAsync();
        if (!permissionResult.granted) {
          alert("需要授予相机访问权限");
          return;
        }
    
        const result = await ImagePicker.launchCameraAsync({
          mediaTypes: ImagePicker.MediaTypeOptions.Images,
          quality: 1,
        });
    
        if (!result.canceled && result.assets[0].uri) {
          setImageUri(result.assets[0].uri);
        } else {
          setImageUri(null); 
        }
      };
      
    
      return (
        <View style={styles.container}>
          <Text style={styles.text}> Upload</Text>
          <Button title="Sélectionner depuis la galerie" onPress={openImagePicker} />
          <Button title="Prendre une photo" onPress={openCamera} />
          {imageUri && <Image source={{ uri: imageUri }} style={styles.image} />}
        </View>
      );
    }
    
    export default UploadScreen;
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        backgroundColor: '#fff',
        alignItems: 'center',
        justifyContent: 'center',
      },
      text: {
        color: '#0C1947',
        fontSize: 20,
        marginBottom: 20,
      },
      image: {
        width: 300,
        height: 300,
        marginTop: 20,
      },
    });
    
  3. 清理并重启服务
    清除Expo缓存后重启应用:

    npx expo start --clear
    

额外说明

  • expo-permissions已被废弃,expo-image-picker自带权限请求方法,无需额外依赖。
  • 你已在app.json中配置的权限描述会被Expo自动识别,无需额外修改。

内容的提问来源于stack exchange,提问作者Zway

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 09:00:24