ReactNativeでExpoSDKのSpeechを利用した、褒められチャットの実装

React Nativeの記事、第三回です。前回と前々回の記事は、以下をご参照ください。

ReactNativeのチャットアプリ開発OSS「react-native-gifted-chat」を利用してみた - このすみろぐ

MacでReactNativeの開発環境の構築と、create-react-native-appで作成されるプロジェクトの説明 - このすみろぐ

さて、前回の記事では「react-native-gifted-chat」を使えば、チャットが実装できるところまでを行ないました。

その後はチャットを喋らせたいと思いまして、音声発音系のReactNativeライブラリを探していたのですが、なんと音声ライブラリがExpoSDKに実装されていることが分かったので、挑戦してみた次第です。

Expo SDKには、音声や地図を始め色々と揃っている

これは私がExpoのことをよく知らなかったのが原因なんですが、Expo SDKのドキュメンテーションを見ると、音声、地図、GPSなどの機能が揃ってます。

Speech - Expo Documentation

Location - Expo Documentation

つまり、Expoを使用する場合には、GPSのような端末機能も「ExpoのSDK」を使って操作する必要があると理解しました。

当初はそれを知らずに、npmで必死に音声ライブラリを探していたのですが、それは不要であるということです。

Expo.Speech.speakによる褒められ音声のサンプル

予め言っておきますが、音声は機会的で、おそらく普通の人であれば「キモイ」という感想で片付けられてしまいそうな気がします(苦笑い)。

一応、「Expo.Speech.speak」に褒めさせるなんてことをせずに、普通に文章を読ませるだけであれば、十分実用には足ると言う事だけは補足しておきます。

www.youtube.com

www.youtube.com

f:id:konosumi:20180505162604p:plain

f:id:konosumi:20180505162741p:plain

Androidにおける音声発声の課題点

意気揚々とGoogle Play Storeにアプリを並べようと思ったのですが、どうにもこうにもAndroidでは動作が不安定です。

シミュレータの問題なのかもしれませんが、日本語読み上げに対応していないデバイスもあるらしく、いくつかのシミュレータで試しましたが、Androidデバイスではあまり喋ってくれません。

・・・なので、Google Play Storeに並べようと思ったのですが、もう少ししっかり調査しないと、プレイストアに並べるのは難しいかもしれません。

ただ、Androidエミュレータはデフォルトが英語設定である事が多いので、AndroidのOS設定を日本語にしたら直るかもしれません(要調査)。

GitHubのサンプル

前回の記事と同じく、サンプルはGitHubにおいてあります。昨日の深夜に夜な夜な書いて疲れてしまったので、気の利いたコメントはありません。

GitHub - konosumi/blog_0175_react_native_expo_speech: React Native の ExpoSDKを使った、Expo.Speech.speakによるサンプルです。

なので、ブログで技術的な内容について、軽く補足しておきます。

(技術解説)ReactNativeにおける画面遷移について

オフィシャルを見ると、画面遷移についての解説は以下のように書かれています。

If you'd like to achieve a native look and feel on both iOS and Android, or you're integrating React Native into an app that already manages navigation natively, the following libraries provide native navigation on both platforms: native-navigation, react-native-navigation.

引用: https://facebook.github.io/react-native/docs/navigation.html

平たく言ってしまえば、「react-navigation」か「react-native-navigation」を使いましょうということです。

さて、この2つを比較すると「react-navigation」の方がお手軽です。何故かと言うと「react-native-navigation」はインストールに一手間加える必要があるのに比べて、「react-navigation」はJSの世界で全てを完結させることが出来るからです。

参考(react-native-navigation)

https://wix.github.io/react-native-navigation/#/installation-ios

https://wix.github.io/react-native-navigation/#/installation-android

参考(react-navigation)

https://reactnavigation.org/docs/getting-started.html:url

(技術解説)react-navigationによる画面遷移

react-navigationは、単に使うだけであれば難しくはありません。

サンプルでは、App.jsにて予めStackNavigatorに画面スタックをセットしています。その後は、navigate関数を経由して、自由にスタック内の画面を行き来することができます。

  • App.js (StackNavigatorによるナビゲーションの組み立て)
import { StackNavigator } from 'react-navigation';
import HomeScreen from './HomeScreen';
import ChatScreen from './ChatScreen';

export default StackNavigator({
  HomeScreen: {
    screen: HomeScreen,
    navigationOptions: ({ navigation }) => ({
      title: '褒められ設定',
    }),
  },
  ChatScreen: {
    screen: ChatScreen,
    navigationOptions: ({ navigation }) => ({
      title: `${navigation.state.params.modeName}`,
    }),
  }
});
  • HomeScreen.js (navigateによる画面の移動)
onPressButton(mode, modeName) {
    if (!this.nickname) {
      Alert.alert('ニックネームを入力してください');
      return;
    }
    Keyboard.dismiss();

    const { navigate } = this.props.navigation;
    navigate('ChatScreen', { mode: mode, modeName: modeName, nickname: this.nickname });
} 

(技術解説)react-navigationによる遷移パラメータの受け取り

navigateの第2引数は、パラメータの受け渡しに利用します。渡されたパラメータは「this.props.navigation.state.params」に入っています。

以下は、HomeScreenから渡されたパラメータを受け取っている例です。

  • ChatScreen.js (ナビゲーション経由でのパラメータの受け取り)
componentDidMount() {
  this.isMountFlag = true;
  this.nickname = this.props.navigation.state.params.nickname;
  this.mode = this.props.navigation.state.params.mode;
  this.chats = ChatConst.LOVE_CHAT(this.nickname);
  if (this.mode == "work") {
    this.chats = ChatConst.WORK_CHAT(this.nickname);
  }

  this.speakMessageChat(0);
}

(技術解説) Expo.Speech.speakによる音声の発声

音声の発声自体は「Expo.Speech.speak」を利用するだけですので、特筆すべきことはありません。

  • ChatScreen.js (Expo.Speech.speakによる発声)
Expo.Speech.speak(speakMessage, {
    language: "ja",
    onDone: () => {
       finishHandler();
    }
    onError: (error) => {
      console.log("error");
      console.log(error);
   }
});

speakMessageはただの文字列です。onDoneは完了ハンドラ、onErrorはエラーハンドラです。エラーをログに出してますが、Androidでエラーが起きてもエラーは空でした。。

ちなみに、使い方に関しては素直に公式の解説を見たほうが早いです。

Speech - Expo Documentation

最近よく思うんですけが、JS関係は素直に公式ドキュメントを見るのが一番良いです。無理に日本語資料を探そうとすると、古くて動かなかったりしてハマります。

さいごに

作ってみたアプリは、ただ単に褒められたいという欲求だけに駆られて作ったのですが、機会音声感が残っているため、物凄く微妙なアプリになってしまいました(苦笑い)。

収穫としては「Expo SDK」には色々揃っていることが分かったので、地図や GPSのような、端末の機能を使ったアプリであってもJSで開発できるという点です。

補足:OSによる挙動の違いについて

サンプル内でもOSによる切り替えを書いてますが、OS毎によって微妙な挙動の違いがあるため、両OSでの動作確認は必須です。

  • HomeScreen.js (ButtonのcolorはOSによって解釈が異なる)
<View style={styles.loveButton}>
  <Button
    onPress={(e) => this.onPressButton("love", "恋愛")}
    color={ Platform.OS === 'ios' ? "#000000" : '#FFC0CB'}
    title="恋愛"
  />
</View>

ちなみに、公式リファレンスにも注意事項が書いてあったります。

そのため、ReactNativeで開発する時は、常に公式リファレンスを片手に開発することを推奨します。

color: Color of the text (iOS), or background color of the button (Android)

引用:https://facebook.github.io/react-native/docs/button.html