React Native Expoで始めるモバイルアプリ開発

モバイル開発

皆さんはモバイルアプリを開発してみたいと思ったことはありますか。 AndroidやiOSといったプラットフォーム向けにアプリを作るには、JavaやKotlin、Objective-CやSwiftなどの言語が必要だと考えるかもしれません。 しかしJavaScriptの経験を活かして、単一のコードベースでiOSとAndroidに対応する方法があります。 それがReact Nativeを活用した開発です。 そして、React Nativeをもっと気軽に扱えるように整備されたツールチェーンがExpoです。 Expoを利用すると、開発やビルドの手順がシンプルになり、初心者でも取りかかりやすくなります。 この記事では、React Native Expoの基本から環境構築、主な機能、そして簡単なサンプルアプリの実装例までを解説します。

ここで解説している内容は、プログラミング未経験者や初学者の皆さんにもわかりやすいように書いています。 ReactやJavaScriptの基本を少し知っている方なら、さらに理解しやすくなるかもしれません。 最初は戸惑うことがあっても、Expoを使えば開発に集中しやすくなり、アプリの動作を素早く確認できます。 それでは順を追って見ていきましょう。

React Native Expoとは

React Nativeを使ったことがない方は、「Expo」という言葉を聞いてもピンとこないかもしれません。 まずは、React NativeそのものとExpoの関係を見ていきましょう。

React Nativeの概要

React NativeはFacebook(現Meta)が開発したフレームワークで、JavaScriptJSX記法を使ってネイティブアプリを作ることを可能にします。 Webでよく使われるReactの文法をベースにしているため、Reactに親しんでいる方は直感的に書けるはずです。 また、React NativeではネイティブのUIコンポーネントを利用する仕組みになっているので、ユーザーが操作したときの挙動や見た目はAndroidやiOSの標準仕様に近いものになります。

実務においては、既存のネイティブアプリ開発(JavaやKotlin、Swiftなど)と比べてリリースまでのスピードを重視したい場合や、Webエンジニアがモバイル開発にスムーズに入っていきたい場合にReact Nativeは採用されることがあります。 とはいえ、React NativeはReactやNode.js周りのツールチェーンに慣れていない方にとって、セットアップが複雑に感じられることがあるでしょう。 JavaScriptやReactの学習だけでなく、Android Studioの設定やXcodeの設定など、多岐にわたる前準備が必要になるからです。

Expoが担う役割

この前準備の面倒さを簡略化しようとするのがExpoです。 ExpoはReact Nativeに特化したツールとサービスの一式で、環境構築やビルド、テスト、配布などがまとめて整備されています。 たとえば、下記のような場面でExpoのメリットを感じることが多いです。

  • コマンド1つで新しいReact Nativeプロジェクトをすぐに作成できる
  • AndroidやiOSのエミュレータ、実機へのデプロイのフローが簡単になる
  • 画像やプッシュ通知、カメラ、センサーなど、モバイル特有の機能をまとめて扱える
  • ビルドやストアへの提出が一貫した手順で行える

実際の現場では、小規模から中規模のアプリや、試作段階のプロトタイプ、内製ツールのモバイルアプリ版などでExpoが使われることが多いです。 ネイティブコードを直接いじりたい高度な要件がある場合は、Expoから“Eject”という手順を踏むことで純粋なReact Nativeプロジェクトへ切り替えることもできます。 初心者の皆さんがまず学ぶには、Expoを使うほうが心理的なハードルが下がるでしょう。

なぜExpoを選ぶのか

Expoを使う理由はさまざまですが、特に大きいのは以下のメリットです。

環境構築がシンプル

ネイティブ開発環境のセットアップを極力少なくできるため、初心者でも始めやすいです。

豊富なライブラリの統合

Expoにはカメラやオーディオ、位置情報といった機能にアクセスするライブラリが用意されています。 これらを追加の設定なしで使えるのは魅力的です。

ビルドや配布の手順が確立されている

Expo CLIやExpo Dev Toolsを使うことで、一貫性のあるビルドとテストが可能になります。

学習コストを抑えたい方や、素早く成果を出したい方にはExpoがぴったりではないでしょうか。 また、プロジェクトが大きくなってネイティブモジュールを細かく操作したいという段階になったら、Ejectして自由度を高めることもできます。

React Native Expoに対するよくある疑問

ここで、初心者の方が抱えやすい疑問を挙げてみましょう。

  • 「Expoを使ったら、本当にネイティブアプリになるのか?」
  • 「ストアに公開するときは、どうやってビルドすればいいのか?」
  • 「ネイティブコードを扱う必要はないのか?」

Expoで作ったアプリもReact Nativeで動いているので、基本的にはネイティブアプリとして動きます。 ビルド周りはExpoのサービスやCLIツールが自動で最適化してくれるため、ややこしい設定は少なくて済むでしょう。 ネイティブコードの修正が必要なときは、後からExpoの仕組みから離れて必要箇所を調整することも可能です。

実際のところ、大規模アプリや特殊な機能を多く使う場合は、最初からReact Nativeを直接セットアップする会社もあります。 しかし、初期リリースを目指す段階ならExpoを利用して開発スピードを上げることはよくあることです。 皆さんが初めてモバイルアプリに挑戦するなら、Expoは頼りになる存在かもしれません。

React Native Expoを使った環境構築手順

次に、React Native Expoを使うときの環境構築手順を紹介します。 ここでは基本的なセットアップの流れと、その背景を説明します。

Node.jsとnpm(またはYarn)の準備

React NativeやExpoはJavaScriptベースなので、まずはNode.jsのインストールが必要です。 Node.jsを入れると、自動的にnpmが使えるようになります。 もしYarnが使いたい場合は、別途インストールしましょう。

実務で開発する場合も、Node.jsとnpmあるいはYarnの組み合わせはよく使われます。 パッケージ管理ツールを通じて、React NativeやExpoをはじめ、さまざまなライブラリを管理できるからです。

Expo CLIのインストール

Expoを使うには、Expo CLIをグローバルにインストールする方法があります。 コマンドは以下のようなイメージです。

npm install --global expo-cli

最近では、公式が推奨しているnpx create-expo-appを使う方法も広まっています。 これは、グローバルにExpo CLIをインストールしなくても、プロジェクト生成時点だけでCLIを利用できる利点があります。 どちらを選んでも結果はほぼ同じなので、お好みの方法を選んでください。

実務のプロジェクトでReact Native Expoを導入するときも、新しいリポジトリでnpx create-expo-appを実行するケースが多いです。 迅速にプロトタイプを立ち上げたい場合に便利でしょう。

プロジェクトの作成

それでは実際にプロジェクトを作ってみましょう。 下記は、npx create-expo-appを使う場合の一例です。

npx create-expo-app my-expo-app
cd my-expo-app
npm start

上記のコマンドを実行すると、必要なファイルが自動的に生成され、ライブラリのインストールも行われます。 あとは、npm startでExpo開発サーバーが立ち上がり、Webブラウザ上のExpo Dev Tools画面が表示されるはずです。

実務では、リポジトリをクローンしてきてnpm installnpm startといった流れが基本です。 Expoなら環境ごとの差異が少ないため、チームメンバーが増えても「自分の環境だと動かない」といったトラブルが起きにくい傾向があります。

エミュレータや実機での確認

Expoは、Expo Goという専用アプリをスマートフォンにインストールすれば、QRコードをスキャンしてすぐに開発中のアプリを実機で確認できます。 AndroidエミュレータやiOSシミュレータを使う場合も、Expo CLIまたはExpo Dev Toolsからワンクリックで起動できます。

実務の視点では、以下のような流れで進めることが多いです。

  • ローカルPCでnpm startを実行し、Expo Dev Toolsを起動する
  • エミュレータもしくは実機(Expo Goアプリを起動)でQRコードを読み取る
  • ネットワーク越しでアプリの動作を確認する

チーム開発では、同じネットワーク上にいるメンバーが、それぞれの端末から同じアプリを起動できるため、デバッグやレビューがしやすくなります。 もしVPN環境やファイアウォールの制限などがあってネットワークの共有が難しい場合でも、Expoの有料プランを使ったトンネリングなどが利用できる可能性があります。

Android StudioやXcodeのインストール

Expoを使えば、Android StudioやXcodeがなくても実行確認ができることがあります。 しかし、Google PlayストアやApp Storeに公開するときには、最終的にビルドが必要です。 Android向けのビルドにはJavaを含むAndroid SDK、iOS向けのビルドにはmacOS上でのXcodeなどが求められます。

初心者の皆さんがまず学習目的で作るだけなら、とりあえずAndroid StudioやXcodeを後回しにしても問題ありません。 ただし、実際にストア公開を目指す段階になったら、これらの公式ツールのインストールやアカウントの登録などが必要になるでしょう。

Expo Dev Toolsの便利さ

ExpoにはGUIベースのExpo Dev Toolsという画面が用意されています。 プロジェクトのビルド設定や、エミュレータの起動、ロギングなどをブラウザ経由で確認できるのが特徴です。

実務でReact Native Expoを使う場合でも、このDev Toolsは便利に使われます。 「どの端末で実行しているか」「ビルドの状況はどうなっているか」といった情報を手軽に把握できるからです。 特に初学者がコマンドラインに慣れていない場合、GUIの操作で確認できるのは安心材料になるのではないでしょうか。

Expoの代表的な機能と実務での使いどころ

ExpoにはReact Native開発を快適にするための様々な機能が詰まっています。 ここでは代表的な機能をいくつか紹介し、どのような実務シーンで活用できるかを考えてみましょう。

カメラ機能の利用

モバイルアプリではカメラ機能を使うことが多いです。 ユーザーのプロフィール画像を撮影したり、QRコードやバーコードを読み取ったりといったシーンが考えられます。 Expoには、expo-cameraというパッケージがあり、簡単にカメラ機能を実装できます。

import React, { useState, useEffect } from "react";
import { View, Text, Button } from "react-native";
import { Camera } from "expo-camera";

export default function CameraExample() {
  const [hasPermission, setHasPermission] = useState(null);
  const [cameraRef, setCameraRef] = useState(null);

  useEffect(() => {
    (async () => {
      const { status } = await Camera.requestCameraPermissionsAsync();
      setHasPermission(status === "granted");
    })();
  }, []);

  if (hasPermission === null) {
    return <Text>カメラの権限を確認中...</Text>;
  }

  if (hasPermission === false) {
    return <Text>カメラの権限がありません</Text>;
  }

  const takePhoto = async () => {
    if (cameraRef) {
      const photo = await cameraRef.takePictureAsync();
      console.log(photo.uri);
    }
  };

  return (
    <View style={{ flex: 1 }}>
      <Camera style={{ flex: 1 }} ref={ref => setCameraRef(ref)} />
      <Button title="写真を撮る" onPress={takePhoto} />
    </View>
  );
}

このように、Expoが提供するコンポーネントを読み込むだけで、ネイティブのカメラ機能を呼び出せます。 実務では、SNSアプリやECサイトのユーザー投稿機能、バーコード決済アプリなどで活かすことが多いでしょう。

位置情報の活用

位置情報は、地図アプリや店舗検索アプリなどで頻繁に使われます。 Expoが提供するexpo-locationを利用すれば、GPSデータを取得して現在地を表示するといった実装が簡単になります。 ネイティブのコードを直接書かなくても、JavaScriptだけで位置情報を扱えるのは効率的です。

実務では、店舗検索やルート案内、配達員の位置管理、観光アプリでの周辺スポット案内などで位置情報が扱われます。 特に初心者がモバイルアプリの特徴を体感するなら、位置情報機能は分かりやすい入り口かもしれません。

プッシュ通知の導入

プッシュ通知はユーザーへのリマインドや新着情報の通知に用いられます。 React Nativeでプッシュ通知を実装しようとすると、AndroidやiOSのネイティブコードに触れる必要が出てくることがあります。 しかしExpoの場合は、expo-notificationsを使って比較的容易にプッシュ通知を扱うことができます。 サーバー側からトークンを使って通知を送る仕組みになっているので、大規模開発でも応用しやすいです。

実務においては、ECサイトのセール情報、チャットアプリの新着メッセージ通知、タスク管理のリマインドなど、プッシュ通知はさまざまな場面で使われます。 Expoなら、まずは簡単にローカル通知やトークンの取得を試してみるところから始められます。

センサーやハードウェアとの連携

スマートフォンにはカメラ以外にも、加速度センサーやジャイロセンサー、マイク、Bluetoothなど多くの機能が搭載されています。 Expoのパッケージ群を活用すると、これらの機能にアクセスできるコンポーネントやAPIが準備されています。 たとえば、万歩計のように歩数を測ったり、端末の向きによって画面の動きを変えたりするといった実装が可能です。

実務では、フィットネス系アプリや音声録音が必要なアプリ、IoTデバイスと連携するような場面でセンサーの情報が求められます。 Expoを使えば、ネイティブコードに詳しくなくてもモバイル端末のハードウェア機能を活かしやすいでしょう。

ビルドと配布

Expoの強みとして、ビルドと配布の一元化があります。 expo build:androidexpo build:iosといったCLIコマンドでビルドを行い、そのままストアへの提出に近い形に仕上げることができます。 また、 OTA (Over The Air) アップデート機能を利用して、コードの変更を即時にユーザーへ配信することも可能です。

実務では、アプリのビルドとリリース作業はプロセスが複雑になりがちです。 ExpoならCI/CDツールと連携しやすい構造になっているので、定期的なビルドやステージング環境でのテストなどを効率化できます。 リリーススピードを重視するプロジェクトでは、Expoのビルド機能が重宝されることがあります。

React Native Expoを活用したサンプルアプリ

最後に、React Native Expoを使ったサンプルアプリの例を示します。 ここでは、簡単な「ToDoリストアプリ」を題材にして、Expoプロジェクトでの実装イメージをつかんでみましょう。

アプリの概要

このToDoリストアプリは下記のような機能を持ちます。

  • ToDoの追加・削除
  • リストの表示
  • 完了・未完了の状態を示す
  • スマートフォンで直感的に操作できるUI

機能は単純ですが、一覧表示やタップ処理など、モバイルアプリの基本的な要素が詰まっています。 皆さんも試してみると、React Native Expoの開発フローが体得しやすいでしょう。

プロジェクト構成

まず、プロジェクトのディレクトリ構成は次のようになります。

my-expo-todo
├── App.js
├── package.json
├── node_modules
└── ...

Expo CLIで作成すると、App.jsがエントリーポイントになります。 このApp.jsにToDoリストの画面や機能を実装していくイメージです。

サンプルコード

以下はシンプルな例です。 これだけで、起動するとToDoリストを操作できるようになります。

import React, { useState } from "react";
import { StyleSheet, Text, View, TextInput, TouchableOpacity, FlatList } from "react-native";

export default function App() {
  const [text, setText] = useState("");
  const [todos, setTodos] = useState([]);

  const addTodo = () => {
    if (text.trim().length === 0) return;
    const newTodo = { id: Date.now().toString(), title: text, completed: false };
    setTodos([...todos, newTodo]);
    setText("");
  };

  const toggleComplete = (id) => {
    const updatedTodos = todos.map(todo => {
      if (todo.id === id) {
        return { ...todo, completed: !todo.completed };
      }
      return todo;
    });
    setTodos(updatedTodos);
  };

  const deleteTodo = (id) => {
    const filteredTodos = todos.filter(todo => todo.id !== id);
    setTodos(filteredTodos);
  };

  const renderItem = ({ item }) => (
    <View style={styles.todoItem}>
      <TouchableOpacity onPress={() => toggleComplete(item.id)} style={{ flex: 1 }}>
        <Text style={[styles.todoText, item.completed && styles.completedText]}>
          {item.title}
        </Text>
      </TouchableOpacity>
      <TouchableOpacity onPress={() => deleteTodo(item.id)} style={styles.deleteButton}>
        <Text style={styles.deleteButtonText}>削除</Text>
      </TouchableOpacity>
    </View>
  );

  return (
    <View style={styles.container}>
      <Text style={styles.title}>ToDoリスト</Text>
      <View style={styles.inputContainer}>
        <TextInput
          style={styles.input}
          placeholder="やることを入力"
          value={text}
          onChangeText={setText}
        />
        <TouchableOpacity onPress={addTodo} style={styles.addButton}>
          <Text style={styles.addButtonText}>追加</Text>
        </TouchableOpacity>
      </View>
      <FlatList
        data={todos}
        keyExtractor={item => item.id}
        renderItem={renderItem}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    padding: 20,
    paddingTop: 50,
  },
  title: {
    fontSize: 24,
    fontWeight: "bold",
    marginBottom: 20,
  },
  inputContainer: {
    flexDirection: "row",
    marginBottom: 20,
  },
  input: {
    flex: 1,
    borderWidth: 1,
    borderColor: "#ccc",
    borderRadius: 4,
    padding: 10,
  },
  addButton: {
    backgroundColor: "#007AFF",
    borderRadius: 4,
    padding: 10,
    marginLeft: 10,
    justifyContent: "center",
    alignItems: "center",
  },
  addButtonText: {
    color: "#fff",
  },
  todoItem: {
    flexDirection: "row",
    alignItems: "center",
    paddingVertical: 10,
    borderBottomWidth: 1,
    borderBottomColor: "#eee",
  },
  todoText: {
    fontSize: 16,
  },
  completedText: {
    textDecorationLine: "line-through",
    color: "#aaa",
  },
  deleteButton: {
    marginLeft: 10,
    backgroundColor: "red",
    borderRadius: 4,
    padding: 5,
  },
  deleteButtonText: {
    color: "#fff",
  },
});

この例では、ReactのuseStateフックを使ってToDoを管理し、タップ処理によって完了状態を切り替えたり、削除したりできるようにしています。 タップの検知にはTouchableOpacityを活用し、リストの表示にはFlatListを使用しています。 これらはいずれもReact Nativeの標準コンポーネントです。 ExpoはあくまでReact Nativeのプロジェクトを簡単に立ち上げるためのプラットフォームなので、React Nativeのコンポーネントをそのまま活用できます。

実務での応用ポイント

このサンプルアプリを拡張していくと、より実務に近い機能を実装できます。 たとえば以下のようなアイデアがあります。

  • タスクの期限や優先度を追加して管理をしやすくする
  • プッシュ通知で期限が近いタスクをリマインドする
  • APIサーバーと通信して複数端末でToDoを同期する
  • ユーザー認証を導入して個人ごとにタスクを管理できるようにする

Expoなら、プッシュ通知の追加や外部APIとの通信をスムーズに取り入れられます。 実務ではこれらの機能を組み合わせて、チームタスク管理アプリや学習計画アプリなどに発展させるケースがあるでしょう。

React Native Expoでは、マルチプラットフォーム対応のアプリを効率よく作れます。 開発を重ねるうちにネイティブコードの修正が必要になったら、Ejectによって自由度を高めることもできます。

さらなる発展: EAS(Expo Application Services)

Expoには、ビルドやデプロイを一括で支援する EAS (Expo Application Services)という仕組みがあります。 EASを使うと、アプリをクラウド上でビルドしてiOS/Androidそれぞれのアプリファイルを生成したり、ストアへの提出を支援してくれたりするため、ローカルPCの環境に依存しない開発フローを実現できます。 大人数のチームで開発を行うときや、CI/CDパイプラインを確立して自動的にビルド・デリバリーしたいときなどに役立つでしょう。

実務のプロダクトでは、EASを使うことで環境による差異を減らし、ビルドの安定性を高める取り組みが行われています。 たとえば、WindowsユーザーやmacOSユーザーが混在したチームでも、EASならクラウドでビルドするのでローカルの依存が少なくなります。 それにより、メンバー全員が同じ手順でビルドできる点は大きな利点といえます。

まとめと次のステップ

ここまで、React Native Expoを使ったモバイルアプリ開発の概要と、実際のセットアップ方法、主な機能やサンプルアプリの例を紹介しました。 Expoを使えば、ネイティブ開発にありがちな複雑な環境構築を簡略化できるため、初心者の皆さんでもモバイル開発に取り組みやすくなるはずです。 また、カメラやプッシュ通知といった機能の活用方法も覚えれば、実務で求められる幅広いニーズに応えやすくなるでしょう。

React NativeやExpoはコミュニティが活発で、公式のドキュメントやサンプルも充実しています。 日本語の情報も少しずつ増えているので、わからないところがあればまずは公式リファレンスやGitHubのIssueを参考にしてみてください。 そうすることで、React Native Expoが抱えている最新動向やベストプラクティスを学べるかもしれません。

Expoを使いこなすと、コードを修正するだけで複数のプラットフォームのアプリを一括でアップデートできたり、リリースまでの時間を大きく短縮できたりします。 特に個人開発や小規模プロジェクトで「試作のスピード」を重視する際には頼もしい手段ではないでしょうか。 そして、機能がどんどん複雑になってネイティブコードに踏み込む必要が出てきたら、ExpoプロジェクトをEjectしてReact Nativeに移行する道もあります。

React Native Expoは、初心者から上級者まで幅広い層が使いやすいフレームワークです。 最初はExpoを活用し、必要に応じてネイティブ開発へ切り替える方法も視野に入れると、柔軟なアプリ開発ができます。

皆さんも、まずは簡単なサンプルアプリを作って、React Native Expoの操作感に慣れてみてください。 少しずつ機能を追加していくことで、モバイルアプリ開発の魅力を味わいやすくなるかもしれません。 React Native Expoで制作したアプリが、将来的に何らかのサービスで活躍する可能性もあるでしょう。 皆さんのアイデアを形にするうえで、React Native Expoはしっかりとした基盤になってくれるはずです。 ぜひ、チャレンジしてみてください。

React Nativeをマスターしよう

この記事で学んだReact Nativeの知識をさらに伸ばしませんか?
Udemyには、現場ですぐ使えるスキルを身につけられる実践的な講座が揃っています。