Skip to content

expo技术探索

发布日期:2023-08-08

工作项目突然有了 app 开发的安排,于是从 react-native 开始着手学习 app 开发,expo 是官方推荐的脚手架,本文将通过 expo 了解跨平台 app 开发


前言

作为前端开发者,app 是通往大前端的必经之路,而作为非原生开发者,最好的解决方案是使用跨平台的框架。目前市面上流行的跨平台 app 框架主要有 react-native、flutter、uniapp。本文将会探索基于 expo 的 react-native 技术,从零开始开发一个浏览器套壳 app,实现套壳 app 需要的基本能力。

expo

expo 是一个 react-native 的框架,可以认为是框架的框架。有以下几个优点:

  1. 一系列方便的 sdk,帮助我们调用跨平台的原生能力,比如调用相机、扫码、打开 webview 等等。
  2. 开发者可以在不接触原生代码,不接触 xcode、android studio 的情况下完成开发。
  3. 提供了真机调试工具(expo go),在编辑器中保存,即可在调试工具中实现热更新,开发体验非常友好。

开发前,需要注册一个 expo 账号,然后可以在 expo 的控制台中查看构建的包。当然了,如果没有加入苹果开发者计划,或者没有苹果开发者计划的管理权限,那么在构建的时候将会寸步难行。

另外,expo 没有中文文档,学习时需要查阅英文文档;遇到困难时,不妨同时查阅下 react-native 文档,国内讨论度较低,遇到问题需要使用英文搜索

expo go

expo 提供的真机调试工具,可以在安卓和 ios 上安装。

在安卓上安装比较费劲,需要在 google play 中下载安装,没有提供可以直接下载的 apk。我在登录安卓 expo go 的时候还遇到了浏览器问题,导致无法登录,在升级浏览器之后问题解决,推测是 expo 登录时使用了某些先进的浏览器 api。使用安卓扫调试码的时候,没有任何反应,最终要手动输入 expo://192.168.x.x:8081 这种形式的地址,才能够连接上开发服务,开始真机调试。

重点关注的原生能力

从 web 前端开发,到 app 开发,必然是为了一些 app 特有的原生能力,不然直接用 web 开发就好了。为了实现一个套壳浏览器 app,以下是一些重点关注的原生能力,我将会逐一尝试在 expo 中实现:

  1. webview
  2. 调用相机相册、扫码
  3. 消息推送
  4. 地理位置

创建一个新项目

以下命令将会创建一个使用 ts 和 expo-router 的项目模版,在写这篇文章时,最新的sdk版本为49。使用 expo-router 可以很方便地在页面之间导航。

npx create-expo-app@latest --template tabs@49

webview

使用 webview 非常简单,只需要根据文档指引安装。

安装之后,参考react-native-webview文档

下面是 webview 与 app 通讯的代码示例

javascript
// app 向 webview 通讯
// 注入的js,这里通过 prop 注入 webview
const injectJs = `
window.isNativeApp = true;
document.body.style.backgroundColor = 'red';
setTimeout(function() { window.alert('hi') }, 2000);
true; // note: this is required, or you'll sometimes get silent failures
`
let webref = null

// jsx
<WebView 
  ref={(r) => webref = r}
  source={{ uri: 'http://10.228.91.0:3000/' }} 
  onMessage={(event) => {
    console.log(event.nativeEvent.data) // Hello!
  }}
  injectedJavaScriptBeforeContentLoaded={injectJs}></WebView>

webref.injectJavaScript(`window.alert('hello')`) // 还可以动态注入js

// webview 向 app 通讯
const isNativeApp = window.isNativeApp // 获取 app 注入的环境变量
window.ReactNativeWebView.postMessage("Hello!") // 向 app 通讯

总的来说,在 expo 上使用 webview 是非常方便的,几乎没有遇到技术门槛。

调用相机相册、扫码

相机调用同样非常简单,查看文档expo-camera,如果需要扫码能力,也可以在这个组件中实现,不过需要先安装expo-barcode-scanner,要保存照片到相册,需要安装(expo-media-library)[https://docs.expo.dev/versions/latest/sdk/media-library/]。调用以上的能力前都需要获取用户授权的权限,否则会调用失败。

消息推送

消息推送包括本地 app 推送和服务器消息推送。

使用服务端消息推送时,首先生成设备 token 上传到服务器,要发消息时,带着设备 token 请求 expo 的服务器。expo 服务器将会调用 FCM 与 APNs 分别进行消息推送。其中 FCM 指的是谷歌的 Firebase,是安卓的消息推送平台,在国内无法使用。APNs(Apple Push Notification service) 是苹果的消息推送平台。

了解iOS消息推送一文就够:史上最全iOS Push技术详解

由于安卓无法使用 Firebase,尝试使用极光推送的服务,它提供了 react-native 的sdk,然而expo不支持第三方sdk, 即不支持react-native link 这种方式,因此需要还原到半原生的开发模式(expo prebuild)。

地理位置

根据知乎上的评论,expo 在安卓上的定位使用 google 服务,在国产手机上无法使用。而作为一个国内特色问题,中文搜索不到 “expo 安卓 定位” 的相关内容。

尝试打包 app

打包 expo 的开发包基本没有遇到问题,但是 expo 开发包总是带着 expo 的壳子,尝试打包一个完成的生产包:

  1. 安卓打包 eas build --platform android 中途报错Build failed: Gradle build failed with unknown error. See logs for the "Run gradlew" phase for more information.,提示Run gradlew报错了。报错信息可以在 expo 后台看到,类似下面的错误有好多个:
> Task :app:createBundleReleaseJsAndAssets
[stderr] /home/expo/workingdir/build/android/app/build/generated/assets/createBundleReleaseJsAndAssets/index.android.bundle:970:42: warning: the variable "fetch" was not declared in anonymous function " 25#"
[stderr] value: wrapFetchWithWindowLocation(fetch)
[stderr]                                    ^~~~~
...
...

在 github 上有不少人遇到这个问题,暂时没有解决方法

github 相关 issue 尚未被解决

  1. ios 打包,由于没有苹果开发者管理权限,无法生成签名,无法打包

总结

作为不懂原生开发的前端,在国内使用 expo,需要面对以下几个问题

  1. expo 使用 google 实现安卓推送服务,国内不支持;第三方推送平台不支持 expo 工具链,需要回退到 react-native 工作流
  2. expo 使用 google 实现安卓定位服务,国内不支持
  3. expo 国内使用很少,作为非原生开发人员,遇到一些国内特色问题很难找到解决方法;大部分问题需要用英文找到答案
  4. 新版 sdk 会遇到一些奇怪的问题,官方还没有解决办法

利用 expo 开发 app 开发非常方便,但是遇到问题就变得更难解决。其中一些解决方法是 eject(新版改为 prebuild),要了解怎样使用 prebuild,就要从 react-native 开始学习。下篇文章将会回退到 react-native, 再来尝试开发一个 app。

Power by vitepress