SANDFISH FACTORY

技術ブログです。python・vuejsを愛でる日々について綴ります

Vue NativeでiOSアプリを作ってみた

はじめに

cordova + vue.jsの構成でアプリを作ったことはあるんですが、WebView周りのバージョン違いで挙動が異なったり、結構困った場面に遭遇したので、違うアーキテクチャを模索していました。
ちょうど1年前にVue Nativeのことを知ったんですが、試したことがなかったので、今回チャレンジしてみました。
Vue Nativeについての説明は他の方もブログで記載しているので割愛します。

試した環境

  • Node.js : v8.12.0
  • yarn : 1.17.0

環境構築

Vue Nativeのドキュメントをもとに環境構築をします。

vue-native.io

今回の環境や手順は2019/11/7時点で以下の動作ができた状態です。

  • インストールできた
  • iosシュミレーターが動作した
  • native版のvue-routerが動作した

1週間色々試しましたが、vue-native内で利用されているreact-nativeや関連モジュールのバージョンの組み合わせでうまく動かないことがあったので、なるべく楽にそれらを解決した手順になっています。
ソースコードはこちらです。

ドキュメントみるとわかるのですが、vue-nativeはreact-nativeをラッパーしています。 そのため開発環境としてexpoかreact-native-cliのどちらかで環境を作ることができます。
試した結果ではexpoでexpo用のプロジェクトを作り、それからreact-native用のプロジェクトに変換するのが一番手間が少なかったので、そちらの手順を説明します。

cliをインストールする

vue-nativeとexpoのcliをインストールする。

yarn global add vue-native-cli
yarn global add expo-cli

vue-nativeのプロジェクトを作る

vue-native-cliのコマンドでプロジェクトを作り、動作確認をします。
途中でアプリ名を求められるので入力します。

vue-native init blogapp

f:id:sandfish03:20191108080410p:plain
initを実行するとnameの入力を求められる(入力前)

f:id:sandfish03:20191108080543p:plain
initを実行するとnameの入力を求められる(入力後)

Yarn v1.17.0 found. Use Yarn to install dependencies?

と聞かれるので、Yesで実行します。

プロジェクトが生成されているので、プロジェクト内に移動してからiosシュミレーターを起動することができます。

cd blogapp
yarn ios

f:id:sandfish03:20191108081631p:plain:w200
iOSシュミレーター起動

必要なパッケージをインストールする

vueでプロジェクトでvuex、vue-routerを利用するので、関連したパッケージをインストールします。
vuexはそのまま利用しますが、vue-routerはnative用のvue-native-routerをインストールします。

yarn add vuex --save
yarn add vue-native-router --save

依存関係を解決する

このまま、vue-native-routerを利用するとエラーになり、動作しません。 事前に他のパッケージをインストールする必要があります。

yarn add react-native-reanimated --save
yarn add react-native-gesture-handler --save
yarn add react-native-paper --save
yarn add react-native-vector-icons --save

上の3つについてはVue Nativeのドキュメントに記載されているのですが、「react-native-vector-icons 」だけは記載されていません。
どこかのバージョンから追加インストールは必要なくなるかもしれないので、ご注意を。

サンプルアプリを作る

ひとまず、プロジェクトディレクトリの直下に「router」、「store/modules」、「views」ディレクトリを作ります。

f:id:sandfish03:20191109092235p:plain:w200
サンプルアプリのディレクトリ構成

各プログラムの説明は次回の投稿で行いますので、説明は割愛します。
以下のコードをサンプルアプリ内に作ってください。

App.vue

<template>
  <app-navigator></app-navigator>
</template>

<script>
import AppNavigator from './router'
export default {
  components: { AppNavigator },
}
</script>

router/index.js

import {
  createAppContainer,
  createStackNavigator,
} from "vue-native-router";

import Login from "../views/Login.vue";
import Home from "../views/Home.vue";

const StackNavigator = createStackNavigator(
  {
    Login: Login,
    Home: Home,
  },
  {
    initialRouteName: 'Login',
  }
);

export default createAppContainer(StackNavigator);

store/index.js

import Vue from 'vue-native-core'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({})

views/Login.vue

<template>
<view class="container">
  <text class="label">USER ID</text>
  <text-input class="fixed" v-model="userid" />
  <text class="label">PASSWORD</text>
  <text-input class="fixed" :secureTextEntry="true" v-model="password" />
  <button :on-press="doLogin" title="ログイン" />
</view>
</template>
<script>

export default {
  data: function() {
    return {
      userid: '',
      password: ''
    }
  },
  props: {
    navigation: {
      type: Object
    }
  },
  methods: {
    doLogin: function() {
      this.navigation.navigate("Home",{userid: this.userid, password: this.password})
    }
  }
}
</script>
<style>
.container {
  background-color: white;
  justify-content: center;
}

.text-color-primary {
  color: blue;
}

.label {
  margin: 8px;
  align-items: flex-start;
}

.fixed {
  height: 40;
  width: 90%;
  margin: 8px;
  borderColor: gray;
  borderWidth: 1;
}
</style>

views/Home.vue

<template>
<view class="container">
  <text>{{ "USER ID:" + userid }}</text>
</view>
</template>
<script>
export default {
  data: function() {
    return {
      userid: '',
      password: '',
    }
  },
  props: {
    navigation: {
      type: Object
    }
  },
  created: function () {
    this.userid = this.navigation.state.params.userid
    this.password = this.navigation.state.params.password
  }
}
</script>
<style>
.container {
  background-color: white;
  justify-content: center;
  margin: 8px;
}

.text-color-primary {
  color: blue;
}
</style>

プロジェクトを変換する

これまでの手順で作成したプロジェクトはexpoのプロジェクトです。

React Nativeプロジェクトに変換する

このプロジェクトをReact Nativeのプロジェクトに変換します。

yarn eject

このコマンドを実行するとcliが質問をしてきます。

f:id:sandfish03:20191109085843p:plain
変換方法を選択する

変換方法は最初の「Bare: I'd like a bare React Native project」を選択してください。

f:id:sandfish03:20191109085759p:plain
yarn eject実行結果

そのあとは、アプリの名前とworkspaceのファイル名を聞かれるので、適宜入力してください。 今回の説明ではblogappと入力しています。

xcodeで開発する準備を行う

「yarn eject」を実行した後にもメッセージが出ますが、iosの場合は以下のコマンドを実行します。

cd ios
pod install

これでReact NativeでiOSアプリを作る環境が整いました。

yarn iosと実行するとexpoのdevtoolが立ち上がらず、MetroとiOSシュミレータだけがたちがあって動作確認ができます。
xcode経由であれば実機でも確認できます。

f:id:sandfish03:20191109093140p:plain:w200
サンプルアプリ実行

最後に

ちょっと情報が不足しているので、ソース解析したり、React Nativeのマニュアル見ながらで少し大変そうです。
もう少しサンプルアプリの構成のブラッシュアップとネイティブコードの呼び出しまではチャレンジしてみたいと思います。