之前公司有个 RN0.54 的老项目,开发体验真是一言难尽,安卓 studio 都下载不到了,各种初始化配置让人头皮发麻。前段时间接手了一个新的 PDA 项目,要开发一个 app,这不机会就来了么,新技术尝尝鲜。(可能也没那么新了)。。。
一、Expo 的好处是什么?
Expo 是一个工具套件,专为简化 React Native 应用的开发、测试和部署而设计。它提供了开箱即用的开发环境,开发者无需配置 Android Studio 或 Xcode,即可快速上手。通过 Expo Go 应用,你可以在真实设备上实时预览和测试代码变化,支持热重载和快速刷新,支持线上打包,大大提高了开发效率。
Expo 提供了丰富的内置功能和跨平台 API,如摄像头、文件系统、推送通知等,帮助开发者轻松构建功能齐全的 iOS 和 Android 应用。它的托管服务(如云构建、OTA 更新)简化了应用的构建和发布流程,无需复杂的本地工具链。
对于不熟悉原生开发的前端开发者,Expo 屏蔽了复杂的原生代码细节,使得开发过程更加顺畅。它特别适合快速原型开发和 MVP 项目,帮助团队快速验证想法并迭代产品。甚至创建出来的初始项目压根就没android 和 ios 的目录,就一个 app,直接无脑堆代码就好了。
此外,Expo 的社区活跃,提供了详尽的文档和支持,确保开发者在遇到问题时能够迅速找到解决方案。对于需要跨平台支持的中小型项目,Expo 是一个高效且灵活的选择。
二、安装依赖
我用的 node 20 环境,首先安装全局脚手架。
1、用淘宝源试下,先切源吧
nrm use taobao
2、没下载的话先 install 一个 20
nvm use 20
node -v
npm -v
npm i -g eas-cli expo-cli
eas是打包用的,expo-cli 就是我们的全局 cli,开发用的。
三、手机设备下载 Expo Go app
貌似要翻墙?
手机打开可以看到这个界面
四、创建项目并启动
npx create-expo-app app
启动项目
npm run start
有多个指令可以运行下试试。
mac如果遇到如下报错可以 装一个watchman
start 后会出现一个二维码
五、真机调试
用手机打开Expo go,使用Scan QR code扫二维码
修改代码重新保存,会热更新
easy~
内嵌一个 webview 试试
打包 apk 后,要用 https 的地址,否则可能打不开。下面会说解决办法。
也是可以正常打开的。
也可以run andiord 或者 start 进行本地模拟器调试
六、webview 通讯
我就以安卓举例了,ios 没试。
通过
webViewRef?.current?.injectJavaScript(`
window.postMessage(${JSON.stringify({
message: JSON.stringify({
ip,
port,
androidId: Application.getAndroidId(),
}),
})}, '*');
`);
在onLoad的时候将数据从 RN 发送给 webview
const webViewRef = useRef<WebView | null>(null);
const sendMessageToWebView = async () => {
webViewRef?.current?.injectJavaScript(`
window.postMessage(${JSON.stringify({
message: JSON.stringify({
ip,
port,
androidId: Application.getAndroidId(),
}),
})}, '*');
`);
};
const uri = ip?.includes("https")
? `https://${ip}:${port}`
: `http://${ip}:${port}`;
return (
<SafeAreaProvider>
<WebView
style={{
flex: 1,
}}
// style={styles.container}
originWhitelist={["*"]}
javaScriptEnabled={true}
domStorageEnabled={true}
mixedContentMode="always"
source={{ uri: uri }}
// source={{ uri: `${ip}` }}
ref={webViewRef}
onLoad={() => sendMessageToWebView()}
// injectedJavaScript={''}
onMessage={(event) => {
try {
// 传过来的 data 肯定为字符串,可以跟 web 端约定好交互的数据格式
const data = JSON.parse(event.nativeEvent.data);
console.log("data", data);
} catch (error) {
// handle parse error
}
}}
/>
</SafeAreaProvider>
);
webview 接收
const handleMessage = (event) => {
const data = event.data;
console.log("Received message from RN:", data);
setWebViewData(JSON.parse(data?.message || "{}"));
};
useEffect(() => {
console.log("home 页面");
window.addEventListener("message", handleMessage);
document.addEventListener("message", handleMessage);
return () => {
window.removeEventListener("message", handleMessage);
document.addEventListener("message", handleMessage);
};
}, []);
webview 发送给 RN
window?.ReactNativeWebView.postMessage("message from webview");
RN onMessage接收
<SafeAreaProvider>
<WebView
style={{
flex: 1,
}}
// style={styles.container}
originWhitelist={["*"]}
javaScriptEnabled={true}
domStorageEnabled={true}
mixedContentMode="always"
source={{ uri: uri }}
// source={{ uri: `${ip}` }}
ref={webViewRef}
onLoad={() => sendMessageToWebView()}
// injectedJavaScript={''}
onMessage={(event) => {
try {
// 传过来的 data 肯定为字符串,可以跟 web 端约定好交互的数据格式
const data = JSON.parse(event.nativeEvent.data);
console.log("data", data);
} catch (error) {
// handle parse error
}
}}
/>
</SafeAreaProvider>
七、webview支持 http
到这一步就开始麻烦了,常规的 expo 就搞不了了,要从托管managed工作流中退出到裸漏bare工作流。
1、eject一下,可能比较慢
expo eject
2、在 android/app/src/main/AndroidManifest.xml 文件
application 里添加 android:usesCleartextTraffic="true"
我目前的 application 这一行
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="true"
android:theme="@style/AppTheme"
android:supportsRtl="true"
android:usesCleartextTraffic="true">
八、修改 app 名称、图标、和首屏图
eject 之后在修改 app.json里的配置文件和图片啥的貌似就不生效了。 要去 android 的目录里去修改了。
替换这里的图片,适配不同分辨率。
app 名称在 string.xml 里改一下
android/app/build.gradle 里的versionCode和versionName大包前也修改了下,每次累加一下
为了防止不生效。。。我是同步修改了 app.json
九、线上打包
1、先到expo官网注册一下账号,expo.dev/ ,
2、然后本地登录expo账号,输入:
eas login
3、登录后,输入以下代码,让其自动生成eas.json配置文件。
eas build --platform android
4、全点是就行,没啥讲究
eas.json 文件
5、改造下 eas.json文件,不然打出来的不是 apk 文件。
"release": {
"android": {
"buildType": "apk"
}
}
6、运行打包命令
eas build --platform android --profile release
因为要排队打包,一般要十几分钟,慢的话不太清楚,大家慢慢等待即可。
打包好后,下载安装即可。
我这个搞了 11 分钟。
但是这玩意啥也不弄的话,构建的体积有点大,后续再研究下,应该包含了太多不相关的东西。
本地打包没试,感兴趣的自己尝试下吧。哈哈哈哈哈~~~
十、彩蛋
开发完 h5 之后发现项目现场的 pda 是个老古董,安卓 9 的版本。。。。Android System WebView 是 66.0.3359.158 然后 webview套进去直接白屏,vconsole 还打印不出来报错。人都麻了。。。
这里推荐一个调试方式:
Android
chrome
chorme下载资源需要翻墙,有时候调试会出现白屏或提示404,可以使用edge来调试
- 手机连接电脑,在手机上打开USB调试,并允许
- 电脑打开chrome浏览器,在地址栏输入:
chrome://inspect/
- 界面会显示设备和页面列表,选择需要调试的页面
edge
- 手机连接电脑,在手机上打开USB调试,并允许
- 电脑打开edge浏览器,在地址栏输入:
edge://inspect/
- 界面会显示设备和页面列表,选择需要调试的页面
设备打开 usb调试模式之后就可以在电脑上定位到具体的报错信息,果然是语法不兼容的问题。新项目用的 vite4 进行的打包,最后通过 babel 的低版本转换和 vite 的@vitejs/plugin-legacy做了向下兼容。还是没能处理完。最后把仅剩的那个报错语法直接删了(笑死🤣)。