Hyoban

Hyoban

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

Re: React Nativeのゼロからの旅(1)

RN を書く理由#

1 つは、自分自身がまだ本格的に RN を書いたことがなく、その体験を試してみたいと思ったからです。最近、RSS リーダーの「Follow」に興味を持っていますが、まだモバイル版がないため、学習と実践の対象として利用できます。また、最近仕事を始めたので、仕事の後に自分の書きたいコードを書くモチベーションがなかなか湧かないのですが、目標があると自分に集中しやすくなります。

同時に、学習と開発のプロセスを週ごとに更新する小さなブログを作成することも目標にし、皆さんのご支援をお待ちしています。

準備#

hello world#

さて、言葉を多くせずに最初のアプリを実行しましょう。ただし、「道具を使いこなすためには、まず道具を整える必要がある」ということわざがありますので、まず環境を整えましょう。

一般的には、Xcode をインストールするだけで十分ですが、私のように最近 macOS のベータ版にアップグレードした場合は、いくつかの問題が発生するかもしれません。

  1. App Store で入手した Xcode は、システムバージョンと互換性がないため開けません。
  2. ダウンロードした Xcode ベータ版は直接開けず、「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. コマンドラインで使用するベータ版の Xcode を選択する必要があります。xcode-select -s /Applications/Xcode-beta.app

次に、素晴らしいスケルトンが必要です。私は RN の技術スタックに詳しくないので、State of React Nativeを読んだ後、Twitter で見つけたCreate Expo Stackを選びました。

これは、Expo プロジェクトのスケルトンとして機能するだけでなく、さまざまな主要な技術スタックの組み合わせオプションも提供してくれるため、アプリの開発を早く始めるのに非常に便利です。最終的に私が選んだ組み合わせは次のとおりです。

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 ファイルのUIUserInterfaceStyleキーの値がAutomaticに設定されます。

本題に入る#

さて、それでは Follow アプリを作成しましょう!

アカウントのログイン#

Expo のドキュメントには詳細なAuthentication の統合ドキュメントがありますが、私たちはそれを使用する必要はありません。Follow のウェブサイトで既にログイン処理が完了しているため、私たちは単にウェブサイトのログインを呼び出し、アプリにログイン後にリダイレクトされるスキームリンクを処理するだけです。

まず、アプリのスキームを設定し、アプリの設定でscheme: 'follow'を設定し、expo prebuildを実行します。

expo-web-browserを使用して Follow のログインページを開きます。

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

次に、expo-linkingを使用して URL のリスニングイベントを登録し、ログインウェブページからの URL 情報を受け取った後、その中のトークンを解析します。

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、これでユーザーの認証トークンを取得できるようになりました。API を呼び出してみましょう。

ユーザー情報の取得#

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 では、クッキーベースの認証に関するいくつかの既知の問題があるため、credentials: 'omit'を設定しないと、2 回目のリクエストで正しくないクッキーが設定され、リクエストが失敗する可能性があります。これは、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 を送ることができます。

まとめ#

やっと動作するソフトウェアができました。次の週は何をしましょうか?おそらくアプリにデータベースを設定することでしょうか?アプリを書く場合、弱いネットワークやオフラインの状態でもフィードを正常に閲覧できることを望んでいます。皆さんのアイデアについてお話ししましょう。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。