某Webアプリ、スマホアプリ開発の企業に勤めているエンジニアの日記です。主に、技術系記事や本の要約を発信します。

ReactNative × FirestoreでiOSアプリを作成する手順とまとめ

概要

CloudFirestoreとは

Firebaseが提供している、NoSQLベースのデータベースのうちの一つ(MBaasの一つ)

RealtimeDatabase → CloudFirestoreに進化!

Q、何が改善されてる?

A、データモデルの改善、クエリ強化されている。

Firebaseの機能とデータベース

image.png

準備

Firebaseプロジェクトのセットアップ

Firebase公式ページからコンソール画面に移動して、新規アプリ作成。

プロジェクトIDとロケーションは後で変更が出来ないので、注意!

※国内向けサービスの場合、asia-northeast1(東京)or asia-northeast2(大阪)

バックエンド側のセットアップ

  • Firebase CLIをインストールする。これを使うと、Firebaseを使った開発がより効率的になる。
    npm install firebase-tools
  • デプロイを可能にするためにセットアップする。
    npm firebase login
  • Firestoreをセットアップ

    最初はテストモードで開始。

f:id:t2s-single:20201230204134p:plain

  • npmモジュールの追加
    npm install @react-native-firebase/app

iOSアプリ開発環境のセットアップ

  • CocoaPods経由でFirebaseをインストール。

    Finderで、「プロジェクト名」→「ios」→「podfile」を開く。podfile内にテキストで以下を記述する。

    target 'Project' do
      pod 'Firebase/Core'
      pod 'Firebase/Auth'
      pod 'Firebase/Firestore'
      pod 'Firebase/Functions'
    end

iosアプリにFirebaseを作成するページで以下の流れに沿って進める。

  • pod install
    cd ios/ && pod install
  • Firebase SDKのセットアップ
    npm install @react-native-firebase/app
    npm install @react-native-firebase/auth
    npm install @react-native-firebase/firestore

実装(データの操作)

  • CollectionとDocumentの取得、追加
    import firestore from '@react-native-firebase/firestore';

    // 'Users'というCollectionの、'KHarada'というDocumentを指定
    const userDocument = firestore()
      .collection('Users')
      .doc('kHarada');
        // 取得
        .get()
        // 追加
        .set()
  • AuthenticationアカウントとFirestoreドキュメントの作成

    新規登録画面で入力されたメールアドレス等をfirestoreドキュメントにぶちこむ。

    handleSubmit = async () => {
        try {
        // メールアドレス認証
          let res = await auth()
            .createUserWithEmailAndPassword(this.state.email, this.state.password)
            .catch((err) => {
              console.log(err);
            });
    
        // ドキュメント内に保存するフィールド
            let userData = {
              uid: res.user.uid,
              email: this.state.email,
            };
                    
        // userDataを保存する
            await firestore()
              .collection('users')
              .doc(res.user.uid)
              .set(userData);
              
              console.log('email login success');
              this.props.navigation.navigate('App');
          }

        } catch (e) {
          console.log(e.message);
        }
      };
  • クエリの機能と種類

    クエリを使いこなすことで、firestore内に保存されているデータを制御し、自在に操作することが可能

  • 条件制限

where

Ex, 18歳以上のみ取得したいとき

        firestore()
          .collection('Users')
          // 18歳以上のみ
          .where('age', '>=', 18)
          .get()
  • 件数制限

limit

ドキュメントの数を制限したいとき

        firestore()
          .collection('Users')
          // 18歳以上のみ
          .where('age', '>=', 18)
          // ドキュメントを20こまで
          .limit(20)
          .get()
  • 並べ替え

order By

        firestore()
          .collection('Users')
          // 降順で並べ替え
          .orderBy('age', 'desc')
          .get()
  • 特定のポイントから開始/終了

start At / end At

        firestore()
          .collection('Users')
          .orderBy('age', 'desc')
            // 18歳から30歳まで
          .startAt(18)
          .endAt(30)
          .get()

startAtでリロード後の追加データをどのポイントから取得するのか指定する。

Firestoreの課題

  • マイグレーション

    マイグレーション:ソフトウェアやシステム、データなどを別の環境に移転したり、新しい環境に切り替えたりすること。

    データのエクスポートが出来ない。バックアップする方法がない。

    (このデメリットはさほど気にならない気もする・・)

  • データベース設計

    データの形式が自由なだけあって、フィールドに書き込んだデータの型がわからなかったりする。

    チーム内でのドキュメント作成と共有が重要。

  • 検索

    ネイティブインデックスの作成やドキュメント内のテキストフィールドの検索をサポートしていないので、Algoliaという検索APIを使って、検索周りはそっちに任せる。

Firebaseでバックエンドエンジニア不在のアプリ開発 クックパッドが体感した、メリットと課題 #エンジニアHub - エンジニアHub|若手Webエンジニアのキャリアを考える!

全文検索 | Firebase

Firestoreを今まで触ってみて思ったこと

  • プロジェクトの規模にもよるが、とにかく機能が充実していて、あまり不便さを感じていない。なので、RDBの必要性が見えてこない。
  • Authenticationは多くのSNSと連携することが可能なので、モダンなプロダクトにはもってこい
  • 多くの企業が利用しているせいか、日本語の記事が多い印象。初心者に優しい。

参考ページ

Cloud Firestore | React Native Firebase

実践Firestore (技術の泉シリーズ(NextPublishing))

CodeIgniterのMVCモデル

CodeIgniterのMVCモデルの書き方をメインに書いています。

Controller

  • 静的なページを作成するためのクラスを実装したコントローラを作成する。

    作成するクラスは、system/core/Controller.php の CI_Controller クラスを継承させる。

    引数にページの名前を取る。

    そのページをロードするメソッドは、show()

    class Pages extends CI_Controller {

            public function show($page = 'home')
            {
            }

    }
  • クラスの継承
    • オーバーライド:小クラスと親クラスで同じメソッドを使用した場合、コクタスが優先され、親クラスを上書きする。
  • メソッド

    特殊な役割を持つメソッド

    • デフォルトメソッド:index()
      • 第二メソッドが空の時に実行されるメソッド
    • 再マップメソッド:_remap()
      • デフォルトメソッドより優先して呼び出される(デフォルトメソッド必要なくなる)
      • 通常のURIルーティングは無視される。
    • 出力メソッド:_output()
      • ユーザー側のブラウザにデータを返す手前で何らかの処理を行うことができる。
    • コンストラクタメソッド:クラス名と同名()
      • コントローラクラスが呼ばれた時に一度だけ実行される。
      • コントローラ内で共通で使用するライブラリなどを初期化する場合や決まった処理を毎回実行したい場合に便利。
        function __construct() {
            // 親コントローラクラスのコンストラクタを呼び出す            
            parent::__construct();
        }
  • プライベートメソッド:_任意のメソッド名()
    • URLから直接アクセスできない。
    • 以下のような書き方で、デフォルトメソッドを経由して呼び出される。
        function index() 
        {
            echo $this->_private_method();
        }

        function _private_method()
        {
            echo 'プライベートメソッドです';
        }

View

  • 特徴
    • PHP構文とHTMLタグで記述できる
    • ビュー同士の連携が可能で、階層構造をもたせることができる。
    • ヘルパーやライブラリが直接利用できる。
    • キャッシュ機能がある。
    • Smartyのような疑似変数ができる。
  • Viewの読み込み
    $this->load->view('ファイル名', データの連想配列 or オブジェクト)
    <?php 
       class Hello extends CI_Controller
       {  
            // index()メソッドの中身>>'Hello World'
          public function index() 
          { 
             echo "Hello World"; 
          }

            // about()メソッドの中身>>about.php
          public function about() 
          { 
             $this->load->view('about'); 
          }
          
       } 
    ?>
  • ループ
    • foreach構文を使って繰り返し処理を行う。
    // Controller 

    function index()
    {
        $data["title"] = "サンプル"
        $data["contents"] = array("りんご", "みかん")
        $this->load->view("ファイル名", $data);
    }
    <title><?=$title?></title>
    .
    .
    .
    <ul>
        <?php foreach($contents as $item):?>
        <li><?=$item;?></li>
        <?php endforeach;?>
    </ul>

Model

  • Modelの書き方
    <?php 
       class Model_name extends CI_Model 
       { 
          public function __construct()
          { 
             parent::__construct(); 
          } 
       } 
    ?>
  • Modelの読み込み
    • 読み込み
    // /system/application/models/read/read.phpを読み込みたいとき
    $this->load->model('read/read');
  • メソッドの実行
    $this->read->function();

CodeIgniterのデータベース接続方法

データベースへの接続

なるべく自動接続。理由は手動接続はすべてのコントローラの接続を作成する必要があるため。

  • 自動接続

    application/config/autoload.phpを使用して行う

    php $autoload['libraries'] = array('database');

  • 手動接続

    特定のコントローラのデータベース接続が必要な場合に使う。

    php $this->load->database();

PHPでの開発を始めるので、概要をまとめてみた

役割

  • HTMLを作ること
  • データを管理すること

ローカル開発環境

サーバーにアップせずにPHPが書き換えたHTMLを確認するために必要な作業

必要なインストール

  • PHP
  • Webサーバー

上記はインストールがかなり難しい。

なので、インストールをアシストしてくれる、XAMPPやMAMPを使う。

MAMPとは

MacintoshApacheMySQLPHPを省略してつなげた名前。

簡単にWeb開発環境を立ち上げられるようにするために必要なソフトウェアをパッケージ化したもの。

XAMPPとほぼ一緒。開発元が違う。

RubyPythonを使う人向け。

コードの書き方

// 最初に<?php ?> で囲う。
<?php echo 'こんにちは!';  // こんにちは!と表示される。 ?>  
<?php echo 'こんにちは!' . date('l');  // こんにちは!Mondayと表示される。
?>  

// 変数
<?php 
    $message = 'こんにちは' . date('l');
?>
<?= $message;  // こんにちは!Mondayと表示される ?>  

// 乱数
<?php 
    $n = mt_rand(1, 3)  // 1以上3以下
?>

// ファイルをインポートする
<?php 
    include('ファイル名')
// この記述だけで反映される
// 以降にHTML記述がなければ、閉じタグ不要
?>

// HTMLタグの中に文字列を記述する時
<title>
    <?= htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); // 別ファイルで表示させたい値を、$titleに代入する
    ?>
    PHPのサイト
</title>

// キャスト
<?php
    $x = (string) 10;    // int型の10を、string型の'10'に変換
?>

// 変数を調査するとき
<?php 
    var_dump($x)
?>

// 連想配列(JSだとオブジェクトに近い?)
<?php 
    $hashira = [
        '水柱' => '冨岡義勇'    // key => value
    ];
    echo $hashira['水柱'];  // 冨岡義勇と表示される
    // keyはstring型かint型のみOK
?>

// 関数の定義
<?php 
    function 関数名($引数1, $引数2) {
        // 処理
        return 返り値;
    }
    関数名($実引数1, $実引数2);
?>

// アクセス修飾子
<?php 
    class Human{
    // プロパティ
        public $name;  // プロパティをクラスの外に公開する
        protected $birthday;
        private $gender;  // プロパティをクラスの外に公開しない。基本的にprivate

    // メソッド
        public function walk() {
            echo '歩く'.PHP_EOL;
        }

        public function eat() {
            echo '食べる'.PHP_EOL;
        }
    }
?>

// コンストラクタ(上の続き)
<?php 
    $human = new Human();
    $human -> eat();
    $human -> walk();
?>

Rubyの基礎文法を簡単にまとめてみた

ハッシュ

#key:valueをひとかたまりに格納する
fruits = {"a":"apple", "b":"grape", "c":"orange"} 
puts fruits
puts fruits[:a] #キー値で取り出す

#実行結果
{:a=>"apple", :b=>"grape", :c=>"orange"}
apple


条件分岐

if 条件A
  条件に一致した場合の処理
elsif 条件B
  条件Aと一致せず、条件Bに一致したの時の処理
else
  条件A, Bのどちらにも一致しない時の処理
end


インデント

rubyでは、tabキーでインデントはNG!

スペースキーでインデント作る!


繰り返し処理

for文

list = [1, 2, 3, 4, 5]
for item in list
    puts item
end

#実行結果
1
2
3
4
5


while文

a = 1
while a <= 10 do
    puts a
    a += 1
end

#実行結果
1
2
3
4
5
6
7
8
9
10


例外処理

begin

begin
実行するコード
rescue
例外が発生したときだけ実行されるコード
else
例外が発生しなかったときだけ実行されるコード
end

rescue

begin
実行するコード
rescue
例外が発生したときだけ実行されるコード
else
例外が発生しなかったときだけ実行されるコード
ensure
例外の有無にかかわらず 最後に実行されるコード
end

raise

raise エラーの種類


メソッド

#メソッド
def drinkServer(fruit)
    drink = fruit + 'ジュース'
    return drink
end

puts drinkServer('りんご')

#出力結果
りんごジュース


クラス

メソッドなどの処理全体のひとかたまり

#円についての処理をするクラスを宣言
class Circle #クラス名の最初は大文字
 
  def area_circle
    puts @radius * @radius * 3.14
  end
 
  #関数などが連続するときは間に空行を1行入れること
  def circumference
    puts @radius * 2 * 3.14
  end
 
  def radius=(radius)
    @radius = radius
  end
end
 
#インスタンスを生成
circle1 = Circle.new
 
#半径を入力
circle1.radius = 3
 
#関数を呼び出す
circle1.area_circle
circle1.circumference


継承クラス

class クラス名 < 継承したいクラス名
 
end

初心者のためのRuby入門徹底ガイド【基礎からわかりやすく解説】 | 侍エンジニア塾ブログ(Samurai Blog) - プログラミング入門者向けサイト

とほほのRuby入門 - とほほのWWW入門

20分ではじめるRuby