Hyoban

Hyoban

Don’t do what you should do, do you want.
x
github
email
telegram
follow

Re: 從零開始的 React Native 之旅(一)

為什麼要寫 rn#

一個是我自己還沒正兒八經地寫過 rn,想試試它的體驗怎麼樣。加上最近對 Follow 這個 RSS 閱讀器很感興趣,但是它暫時還沒移動端,可以作為我邊學習邊實踐的對象。再有就是最近開始上班了,自己老是沒什麼動力在下班後寫點想寫的代碼,有個目標更容易讓自己專注。

同時也立個 flag,把學習和開發的過程寫成每週更新的小博客,歡迎大家關注。

準備工作#

hello world#

好了,廢話不多說,讓我們跑起來第一個 app 吧。不過正所謂 “工欲善其事,必先利其器”,我們先準備好環境。

一般來說你只需要安裝好 Xcode 就行了,不過如果你像我一樣,最近升級了 macOS beta 的話,就會麻煩一些:

  1. App Store 裡的 Xcode 是不能打開的,和系統版本不匹配。
  2. 下載完的 Xcode beta 沒辦法直接打開,提示 the plug-in or one of its prerequisite plug-ins may be missing or damaged and may need to be reinstalled.,需要手動安裝 Xcode.app/Contents/Resources/Packages/ 下的安裝包。參見 https://forums.developer.apple.com/forums/thread/660860
  3. 命令行中需要 select 到你在用的 beta 版 Xcode,xcode-select -s /Applications/Xcode-beta.app

然後就是需要一個 nice 的腳手架,我不太熟悉 rn 這邊的技術棧,看完 State of React Native 就選擇了之前在 Twitter 上看到的 Create Expo Stack

它除了作為一個 expo 項目的腳手架之外,還給你提供了很多主流技術棧的組合選項,這對於我想盡快開始寫 app 非常友好。最終我選擇的組合是:

npx create-expo-stack@latest follow-app --expo-router --tabs --tamagui --pnpm --eas

處理深色模式#

腳手架默認為只支持淺色模式,強迫症表示不能接受,所以首先處理一下先。參考這個 issue,我需要修改 expo 的設置為:

{
  "expo": {
    "userInterfaceStyle": "automatic",
    "ios": {
      "userInterfaceStyle": "automatic"
    },
    "android": {
      "userInterfaceStyle": "automatic"
    }
  }
}

然後你的 useColorScheme 就能正常獲得用戶當前選擇的主題模式。不過需要注意的是,修改完這個配置,你需要再執行一次 expo prebuild,確保 Info.plist 文件裡 key 為 UIUserInterfaceStyle 的值為 Automatic

正戲開始#

好了,現在我們來寫 Follow app 吧!

登錄賬號#

雖然 expo 文檔有很詳細的 Authentication 接入文檔,但我們不需要使用它。 Follow 的網頁端已經處理好了,我們只需要調用網頁端的登錄,為 app 註冊處理網頁登錄後會跳轉的 scheme 鏈接就好。

首先設置好 app 的 scheme,在 app config 裡面設置 scheme: 'follow',然後運行一下 expo prebuild

expo-web-browser 打開 Follow 登錄頁面:

await WebBrowser.openBrowserAsync('https://dev.follow.is/login')

然後用 expo-linking 註冊 url 的監聽事件,在接收到登錄網頁調起的 url 信息後,解析裡面的 token。

Linking.addEventListener('url', ({ url }) => {
  const { hostname, queryParams } = Linking.parse(url)
  if (hostname === 'auth' && queryParams !== null && typeof queryParams.token === 'string') {
    WebBrowser.dismissBrowser()
    if (Platform.OS !== 'web') {
      SecureStore.setItemAsync(SECURE_AUTH_TOKEN_KEY, queryParams.token)
    }
  }
})

這裡還遇到的一個問題是 iPhone 上 Safari 的異步函數裡的 window.open 會無效,需要加上 target="_top" 的參數。參考 https://stackoverflow.com/q/20696041/15548365

因為 url 會跳到 auth 這個頁面,我們可以加個讓它跳到主頁的路由 app/auth.tsx

import { router } from 'expo-router'

export default function Auth() {
  router.navigate('/')
  return null
}

OK,這樣我們就已經能夠獲取到用戶的認證憑據了。來試試調個接口看看。

獲取用戶信息#

在 rn 中發起網絡請求看起來和 web 沒有區別,我們仍然可以使用自己喜歡的庫。

function useSession() {
  return useSWR(URL_TO_FOLLOW_SERVER, async (url) => {
    const authToken = await SecureStore.getItemAsync(SECURE_AUTH_TOKEN_KEY)
    const response = await fetch(url, {
      headers: {
        cookie: `authjs.session-token=${authToken}`,
      },
      credentials: 'omit',
    })
    const data = (await response.json()) as Session
    return data
  })
}

這裡我暫時做了一點反常的設置,是因為 rn 中基於 cookie 的身份驗證存在一些 已知的問題,如果不設置 credentials: 'omit' 的話,就會在第二次請求時設置不正確的 cookie,導致請求失敗。這裡是參考 https://github.com/facebook/react-native/issues/23185#issuecomment-1148130842 的做法。

有了數據我們就可以渲染頁面,這裡先簡單寫寫:

export default function UserInfo() {
  const { data: session, mutate } = useSession()

  return (
    <YStack flex={1} padding={20}>
      {session ? (
        <YStack>
          <XStack gap={24} alignItems="center">
            <Image
              source={{
                uri: session.user.image,
                height: 100,
                width: 100,
              }}
              borderRadius={50}
            />
            <YStack gap={8}>
              <Text color="$color12" fontSize="$8" fontWeight="600">
                {session.user.name}
              </Text>
              <Text color="$color12" fontSize="$5">
                {session.user.email}
              </Text>
            </YStack>
          </XStack>
        </YStack>
      ) : (
        <Button onPress={handlePressButtonAsync}>Login</Button>
      )}
    </YStack>
  )
}

好了,來看看現在的效果。

啊哦,看起來 Follow 的網頁端還需要做點移動端適配,我又可以水 PR 了。

總結#

總算是有個能跑的軟件了,下週要做什麼呢?或許是給 app 設置數據庫?寫 app 的話還是希望我們可以在弱網甚至無網環境中正常瀏覽我們的訂閱。歡迎大家聊聊自己的想法。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。