Loading...
Loading...
Đảm bảo APK Expo/React Native build ra CHẠY ĐƯỢC standalone trên máy thật (không cần Metro dev server) + chẩn đoán lỗi "Unable to load script" khi app cài vào phone không mở được. Áp dụng cho MỌI project Expo/RN (dùng chung, không phụ thuộc repo). Kích hoạt khi user báo "app không mở được", "cài vào máy rồi bị trắng hình", logcat có "Unable to load script" hoặc "ws://localhost:8081", hoặc trước khi thiết kế build pipeline cho app Expo.
npx skill4agent add hoangsoft90/ai_skills expo-apk-standaloneUnable to load script. Make sure you're running Metro or that your bundle
'index.android.bundle' is packaged correctly for release.
W unknown:ReconnectingWebSocket: Couldn't connect to "ws://localhost:8081/..."
ReactHost: ... Fault reason: Unable to load script.localhost:8081./gradlew assembleDebugexpo exportexpo prebuild --cleanreact {}android/app/build.gradle| RN version | Property đúng trong |
|---|---|
| RN ≤ 0.7x | |
| RN 0.76+ / Expo SDK 5x (0.86) | |
bundleInDebug = true# Property nào thực sự tồn tại trong RN version hiện tại?
grep -n "debuggableVariants\|bundleInDebug" \
node_modules/@react-native/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/ReactExtension.kt
# Cách plugin dùng property đó (debuggableVariants -> variant KHÔNG được bundle):
grep -n "debuggableVariants" \
node_modules/@react-native/gradle-plugin/react-native-gradle-plugin/src/main/kotlin/com/facebook/react/TaskConfiguration.kt<project><project>/plugins/embed-js-in-debug.jsconst { withAppBuildGradle } = require('@expo/config-plugins');
module.exports = function withEmbedJsInDebug(config) {
return withAppBuildGradle(config, (config) => {
const contents = config.modResults.contents;
// Guard bằng MARKER RIÊNG của plugin — không guard bằng tên property:
// file build.gradle sinh ra ĐÃ có sẵn comment mẫu `// debuggableVariants = [...]`,
// guard theo tên property = no-op vĩnh viễn (bug thật đã gặp).
if (contents.includes('// bundle JS into the debug APK')) return config;
const updated = contents.replace(
/react\s*\{/,
'react {\n // bundle JS into the debug APK so it runs standalone without Metro (added by embed-js-in-debug)\n debuggableVariants = []' // đổi theo RN version, xem bảng trên
);
if (updated === contents) {
throw new Error('embed-js-in-debug: could not find "react {" block in app/build.gradle');
}
config.modResults.contents = updated;
return config;
});
};app.jsonplugins"./plugins/embed-js-in-debug"cd <project>
npx expo prebuild --platform android --no-install # sinh android/ cục bộ
grep -n -A4 "react {" android/app/build.gradle # phải thấy debuggableVariants = [] / bundleInDebug = true
grep -n "applicationId" android/app/build.gradle # package phải đúng
grep -n "app_name" android/app/src/main/res/values/strings.xml # tên app phải đúng.gitignore/<project>/android//<project>/ios/adb devices -l # máy có kết nối?
adb install -r app-debug.apk # -r = cài đè (bản cũ)
adb shell monkey -p <package> -c android.intent.category.LAUNCHER 1 # mở app
sleep 4
adb shell "dumpsys activity activities | grep -E 'mResumedActivity|topResumedActivity'" # app có ở foreground?
adb logcat -d | grep -iE "FATAL|Unable to load script|ReactNativeJS|E ReactNative" | tail -30
adb exec-out screencap -p > /tmp/screen.png # chụp màn hình kiểm traUnable to load scriptFATALUnable to load scriptandroid.packageios.bundleIdentifiernameschemeReactExtension.ktbundleInDebugdebuggableVariantsadb logcat -cexpo-build-debug-apk-ghgh-actions-expo-apk-build