React Native中RNPermissionsModule缺失及main未注册错误求助
解决React Native项目中的RNPermissionsModule缺失与"main"未注册错误
问题描述
运行React Native(Expo)项目时持续出现两个错误:
ERROR Invariant Violation: TurboModuleRegistry.getEnforcing(...): 'RNPermissionsModule' could not be found. Verify that a module by this name is registered in the native binary., js engine: hermesERROR Invariant Violation: "main" has not been registered. This can happen if: Metro (the local dev server) is run from the wrong folder. Check if Metro is running, stop it, and restart it in the current project. A module failed to load due to an error, andAppRegistry.registerComponentwasn't called., js engine: hermes
项目依赖配置:
"dependencies": { "@react-native-community/masked-view": "^0.1.11", "@react-navigation/drawer": "^6.6.2", "@react-navigation/native": "^6.1.6", "expo": "~48.0.18", "expo-status-bar": "~1.4.4", "react": "18.2.0", "react-native": "0.71.8", "react-native-check-app-install": "^0.0.5", "react-native-exit-app": "^1.1.0", "react-native-gesture-handler": "~2.9.0", "react-native-permissions": "^3.8.0", "react-native-reanimated": "~2.14.4", "react-native-safe-area-context": "4.5.0", "react-native-screens": "~3.20.0" }, "devDependencies": { "@babel/core": "^7.20.0" }, "private": true
主代码:
import React, { useEffect, useState } from 'react'; import { View, Text, Button, FlatList, Switch, TextInput, TouchableOpacity, Alert } from 'react-native'; import { check, request, PERMISSIONS, RESULTS } from 'react-native-permissions'; import ExitApp from 'react-native-exit-app'; import { NavigationContainer } from '@react-navigation/native'; import { createDrawerNavigator } from '@react-navigation/drawer'; const Drawer = createDrawerNavigator(); const App = () => { const [installedApps, setInstalledApps] = useState([]); const [shortlistedApps, setShortlistedApps] = useState([]); const [timers, setTimers] = useState({}); const [blockedApps, setBlockedApps] = useState([]); const [openedApp, setOpenedApp] = useState(null); useEffect(() => { fetchInstalledApps(); }, []); const fetchInstalledApps = async () => { const permissionStatus = await check(PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE); if (permissionStatus !== RESULTS.GRANTED) { Alert.alert( 'Permission Required', 'Please grant storage permission to fetch the installed apps.', [{ text: 'OK' }] ); return; } try { const apps = await RNInstalledApps.getApps(); const appNames = apps.map((app) => app.appName); setInstalledApps(appNames); } catch (error) { console.error('Error fetching installed apps:', error); } }; const handleAppSelection = (app) => { const isShortlisted = shortlistedApps.includes(app); if (isShortlisted) { const updatedApps = shortlistedApps.filter((item) => item !== app); setShortlistedApps(updatedApps); } else { const updatedApps = [...shortlistedApps, app]; setShortlistedApps(updatedApps); } }; const handleTimeLimitChange = (app, timeLimit) => { const updatedTimers = { ...timers, [app]: timeLimit }; setTimers(updatedTimers); }; const handleTimerEnable = (app, enabled) => { if (enabled) { const updatedTimers = { ...timers, [app]: 0 }; setTimers(updatedTimers); } else { const { [app]: _, ...updatedTimers } = timers; setTimers(updatedTimers); } }; const openApp = (app) => { const timer = setInterval(() => { if (timers[app] > 0) { setTimers((prevTimers) => ({ ...prevTimers, [app]: prevTimers[app] - 1 })); } else { clearInterval(timer); setOpenedApp(app); } }, 1000); }; const handleAppClose = () => { setOpenedApp(null); ExitApp.exitApp(); }; const renderAppItem = ({ item }) => { const timeLimit = timers[item] || 0; const isBlocked = blockedApps.some( (blockedApp) => blockedApp.app === item && blockedApp.day === new Date().getDate() ); const isTimerEnabled = timeLimit > 0; const isAppOpened = openedApp === item; return ( <View> <Text>{item}</Text> <Text>Time Used: {timeLimit}</Text> {isBlocked ? ( <Text>This app is blocked for today.</Text> ) : ( <> <Switch value={isTimerEnabled} onValueChange={(enabled) => handleTimerEnable(item, enabled)} /> <TextInput keyboardType="numeric" value={timeLimit.toString()} onChangeText={(text) => handleTimeLimitChange(item, parseInt(text, 10))} /> <TouchableOpacity onPress={() => handleAppSelection(item)}> <Text>{shortlistedApps.includes(item) ? 'Remove' : 'Add'}</Text> </TouchableOpacity> {!isTimerEnabled && ( <TouchableOpacity onPress={() => openApp(item)}> <Text>{isAppOpened ? 'Close App' : 'Open App'}</Text> </TouchableOpacity> )} </> )} </View> ); }; return ( <NavigationContainer> <Drawer.Navigator> <Drawer.Screen name="Home"> {() => ( <View> <Text>Installed Apps:</Text> <FlatList data={installedApps} renderItem={renderAppItem} keyExtractor={(item) => item} /> </View> )} </Drawer.Screen> <Drawer.Screen name="Blocked Apps"> {() => ( <View> <Text>Blocked Apps:</Text> <FlatList data={blockedApps} renderItem={({ item }) => ( <Text>{`${item.app} - Blocked for Day ${item.day}`}</Text> )} keyExtractor={(item, index) => `${item.app}-${item.day}-${index}`} /> </View> )} </Drawer.Screen> </Drawer.Navigator> </NavigationContainer> ); }; export default App;
解决方案
1. 修复RNPermissionsModule缺失问题
Expo项目不兼容社区版react-native-permissions,需替换为Expo官方权限库:
- 卸载社区版权限库:
npm uninstall react-native-permissions - 安装Expo权限库:
npx expo install expo-permissions - 修改代码中的权限导入与调用:
将原导入语句替换为:
同步更新权限检查逻辑:import * as Permissions from 'expo-permissions';const fetchInstalledApps = async () => { const permissionStatus = await Permissions.getAsync(Permissions.PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE); if (permissionStatus.status !== Permissions.RESULTS.GRANTED) { const requestResult = await Permissions.askAsync(Permissions.PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE); if (requestResult.status !== Permissions.RESULTS.GRANTED) { Alert.alert( 'Permission Required', 'Storage permission is mandatory to fetch installed apps.', [{ text: 'OK' }] ); return; } } // 后续逻辑 };
2. 修复RNInstalledApps未定义问题
代码中使用的RNInstalledApps未导入,且依赖中的react-native-check-app-install不提供该API,需调整:
- 卸载不兼容库:
npm uninstall react-native-check-app-install - 针对Expo环境,选择支持的应用查询方案:
- 若需获取已安装应用,使用Expo官方的
expo-app-info(注意:该库仅提供当前应用信息,如需查询其他应用需使用兼容Expo的第三方库):npx expo install expo-app-info - 若坚持使用社区库,需确保库支持Expo预构建流程,避免原生模块链接问题。
- 若需获取已安装应用,使用Expo官方的
3. 解决"main"未注册问题
该错误通常由前置模块加载失败导致,完成上述修复后执行以下步骤:
- 终止当前Metro服务器:按
Ctrl+C停止进程 - 清理项目缓存:
npx expo start --clear - 重新启动项目:
npx expo start
4. 确认入口配置
Expo项目无需手动调用AppRegistry.registerComponent,只需确保入口文件(如App.js)默认导出App组件即可,你的代码已满足此要求。
内容的提问来源于stack exchange,提问作者Richik Mandal
相关产品推荐
相关产品推荐

