React Native Tech Blog

supported by maricuru (旧maricuru tech blogです)

【React Native】【Expo】ディープリンクを実装する

こんにちは、maricuruのワダ(@takahi5)です。

弊社maricuruは今までアプリのみでしたが、現在Web版も開発しています。
Webとアプリをスムーズに移動できるようにと、ディープリンクを実装してみました♪

今回はExpoでのディープリンクの実装についてご紹介したいと思います。

f:id:wasan:20181101134001p:plain

ディープリンクとは?

特定のアプリに遷移させることの出来るリンクのことです。

例えば、retty://というURLをiPhoneで叩くと、Rettyアプリが起動します。

「ブラウザ➔アプリ」の遷移だけでなく、
「アプリ➔アプリ」の遷移も可能です。

ただRettyアプリがインストールされてないと、エラーになります。
ストアに飛ばすなどのカスタマイズはできないので注意が必要です。

ディープリンクの実装

基本的には Linking に書いてありますが、
要所を整理して説明したいと思います♪

アプリへのリンク

ローカルのシミュレーター、Expo Clientアプリ、スタンドアロンビルド、でリンクURLが異なります。

ローカルのシミュレーターの場合

macローカルのiOSシミュレーターなどで立ち上げる場合です。

exp://localhost:19000 にアクセスするとExpo clientアプリで対象のアプリが起動します。

publish済みのアプリをExpo Clientアプリで開く場合

publish済みのアプリを、iPhoneなりAndroid実機のExpo Clientアプリで開く場合です。

まずpublishしたときのログを確認しましょう。
こんな感じだったとします。

[16:46:56] Published
[16:46:56] Your URL is

https://exp.host/@awesome-company/myapp

この場合は、exp://exp.host/@awesome-company/myapp にアクセスすると、Expo Clientアプリで先ほどpublishしたアプリが開かれるはずです。

スタンドアロンビルドの場合

いよいよ本番向けのスタンドアロンビルドの場合です。

まずapp.jsonに設定が必要です。

// app.json
{
  "expo": {
    "scheme": "myapp"
  }
}

こうすればmyapp://のURLでこのアプリが起動されるようになります!

アプリ起動後の処理

ここまでの実装だと、単にアプリが開くだけです。

本来なら特定の記事やコンテンツを開きたいですね。

URLから起動した場合のアプリ内でのハンドリング

どのようなURLから起動したかを取得

URLをパース

然るべき処理をする

のような流れになります。

まずは起動URLを取得してみましょう。

アプリがすでに起動している場合のハンドリング

Expo.Linking.addEventListener()でコールバックイベントを登録しておきます。

componentDidMount() {
  Expo.Linking.addEventListener('url', _handleOpenURL);
}

function _handleOpenURL(event) {
  console.log(event.url);
}

アプリが起動してない場合のハンドリング

Expo.Linking.getInitialURL()で起動時に渡されたURLを取得できます。

async componentDidMount() {
  const url = await Expo.Linking.getInitialURL();
  console.log(url);
}

URLのパース

情報を渡すにはmyapp://の後に情報を付け足せばOKです。
たとえば myapp://articles/4334にしたとします。

受け取ったURLはurl.parse関数などを使ってパースするとよいでしょう。

import url from 'url';

(中略)

function _handleOpenURL(event) {
  const parsedUrl = url.parse(targetUrl);
  console.log(parsedUrl);
}

パース結果はこのような感じです。

"host": "articles",
"hostname": "articles",
"href": "myapp://articles/4334",
"path": "/4334",
"pathname": "/4334",
"port": null,
"protocol": "myapp:",
"query": null,

このデータを使って、然るべきページに遷移するなどすればよさげですね!

補足(Universal Links)

今回説明したディープリンクは、Custom URL Schemeと言われるものらしいです。

それに変わる手法としてUniversal LinksというのがiOS9から導入されています。

Custom URL Schemがmyapp://articles/999のような特殊URLなのに対して、
Universal Linksはhttps://myapp.com/articles/999のようなhttps経由でアプリを開くことができます。

アプリがない場合は普通にhttps://myapp.com/articles/999のWebページが開かれます。
ウェブサイトもあるならこっちのほうが良さげですね。

ちなみにExpoではBranch というAPIを使えば実現できるらしいです。
まだα版でDangerZoneって書いてありますが...

いずれこのBranchも試してみたいと思います♪

キャンペーンの効果的な運用について考えてみた!

こんにちは、maricuruのワダ(@takahi5)です。

サービスを運営していく中で、ユーザー数や投稿数を増やすためにキャンペーンを実施したりすることがあると思います。

弊社maricuruでも最近はキャンペーンをあれこれ試しながらノウハウを蓄積しようとしています。
今回は、そんなトライ&エラーから学んだことをシェアしたいと思います!

f:id:wasan:20181108112332p:plain

キャンペーンの設計

キャンペーンを始めるときは、まずは誰をターゲットにするかを明確にします。

そりゃ、ターゲットはうちのアプリのユーザーやん!
って思っちゃいますが、もう少しユーザーを細かいセグメントに分けてターゲット化しましょう。

ざっくり分けると

  1. ヘビーユーザーを活性化してトップラインを上げる施策
  2. ライトユーザーを活性化してボトムラインを上げる施策
  3. 新規ユーザーを獲得する施策

などに分類できるのではないでしょうか。

弊社maricuruでは、今までヘビーユーザー向けとライトユーザー向けの施策を行ってきました。

ヘビーユーザーを活性化してトップラインを上げる施策

例えば、ランキングでトップを競う、みたいなのは、ヘビーユーザー向けの施策になります。

初期のRettyはこの手のランキングを用いたキャンペーンを多く実施していたようです。

「Retty」に学ぶ、スタートアップにおける「キャンペーン施策」の重要性 : まだ東京で消耗してるの?
イケハヤ氏のブログに書いてありました。時系列でまとまっているので助かりますね。考察は薄いですが。。

ただランキングで、この人1位!この人2位!と競争を煽るスタイルは、サービスによっては合わないこともあるので注意が必要かと思います。

ソシャゲのような環境なら問題ないと思いますが、コミュニティ系サービスなどでは変に上下関係が生まれるのもよくないのかなとも思います。

けんすうさんを中心としたランキングの是非の議論は面白いです。



maricuruの場合では、投稿数の多いユーザーさんを限定オフラインイベントに招待する、というキャンペーンを実施したことがあります。
トップユーザーのモチベーション向上を期待しつつも、あまり表立って競争を煽りたくなかったのでランキングの表示などはしませんでした。

ライトユーザーを活性化してボトムラインを上げる施策

よくあるのが「初○○の人限定でXX」とかです。

何を始めるにしても、人間は「初めて」のときが一番エネルギーが必要です。
そこをキャンペーンの力で後押ししてあげます。


そのサービスでどんなアクションを取れば、その後のアクティビティが高くなる、という傾向が分かっているならキャンペーンの設計もやりやすいでしょう。

有名な話でいうとFacebookの「5人の友人と繋がったユーザーはその後のアクティビティが高い」というのがあります。
そのような数字が見えているのであれば、友人と繋がることを促すキャンペーンは有効だと思います。


maricuruの場合ではQ&Aという機能があるのですが、
Q&Aで質問したユーザーがその後のアクティビティが高くなるという傾向がありました。

maricuruにはmaricuruアドバイザーという卒花さん(結婚式を終えた花嫁)が1500名以上いるのですが、その方たちがとても親切に即レスで回答してくれるので、質問したユーザーの体験が向上するのも納得できます。


ということで、初質問のユーザー限定でプレゼントを提供するキャンペーンを実施したことがあります。

そのキャンペーンを実施してみてよかったのは、キャンペーン期間中に初めて質問したユーザーさんが、キャンペーン後も質問をしていたことです。
キャンペーンをきっかけに質問したけど、そのときによい体験をしたから、また続けて質問しているのだとすると運営としては嬉しいですね。

こういった動きを見るために、キャンペーン後のアクション継続率は、キャンペーンの重要KPIとして追っています。
キャンペーンが終わって、はいサヨナラ、ではキャンペーンの意味がないですからね。

キャンペーンのインセンティブはどうするか?

インセンティブ(景品)の設定は非常に重要です。

ポイントは、ユーザーの熱量を追い越さないことです。

なぜなら、過剰にインセンティブが豪華だと、そのアプリを使う目的がインセンティブのほうに傾いて本来のモチベーションがすり替わってしまうからです。
あくまで、もともとユーザーが持っていたモチベーションが原動力で、その背中を後押しする程度のインセンティブが適切だと思います。


こんな面白い話を聞いたことがあります。

ある村にイタズラ好きの少年たちがいました。
少年たちは、おじいさんの家の塀に毎日落書きをします。
おじいさんが何度注意しても面白がってやめません。

ある日おじいさんは注意するのではなく、落書きをする度に少年たちにお金を渡すようになりました。
少年たちは 「落書きをしてお金がもらえるなんてサイコーだ!」と喜んで落書きを続けました。

ところがある日、おじいさんはお金を渡すのをやめました。

すると少年たちは「なんで落書きしてるのにお金くれないんだよ!」と不平を言い、落書きをするのをやめました。

実話なのかは知りませんが、
要はお金というインセンティブが強烈すぎて、好きでやっていたはず落書きが、お金目的になっていたというお話です。

このように強烈すぎるインセンティブは、本来楽しんでいたはずの人のモチベーションさえ狂わせかねません。

そういう意味でインセンティブの設計は慎重にやるべきかと思っています。


先に上げた例のRettyも見てみると、賞金総額4万円と意外と少ないです。
おそらく、背中を押す程度の軽めなインセンティブだったのではないかと思います。

まとめ

以上になります。

あくまでプロダクトの魅力があることが前提ですが、効果的にキャンペーンを運用して爆速で成長させたいですね!

【React Native】【Expo】iOS/Android ストア申請用のビルドを作る

こんにちは、maricuruのワダ(@takahi5)です。
寒さに比例して南国に行きたい欲が高まってきております🏖

さて、弊社アプリはExpoで作っていますが、たまに
「Expoで作ったアプリってストアに公開できるの?」
と聞かれることがあります。

もちろんストアに公開できます!

むしろストア公開のステップが大幅に軽減されるのがExpoのメリットだったりします。

  • XCodeでのビルド不要
  • Android Studioでのビルド不要
  • iOSのプロビジョニングとかの管理不要
  • pushのトークンとかの管理も不要

などなど驚きのメリットがあります。

f:id:wasan:20181025124259j:plain

ストア申請用とExpoクライアントアプリの違い

Expoで普段開発しているとExpoクライアントアプリを使うと思います。
QRコードとかで起動できるやつです。

ストアに申請するときには、これとは異なり申請用のビルドを作ることになります。
iOSならipaファイル、 androidならapkファイルですね。

ストア申請用のビルドの作り方

基本的には↓に書いてあります。
Building Standalone Apps - Expo Documentation

要所を説明したいと思います。

app.jsonの設定

bundleIndentifer, packageはitune connect や google play consoleで作成したものを指定しましょう。
buildNumberやversionCodeはビルドを申請するたびにインクリメントする番号です。

 {
   "expo": {
    "name": "Your App Name",
    "icon": "./path/to/your/app-icon.png",
    "version": "1.0.0",
    "slug": "your-app-slug",
    "sdkVersion": "XX.0.0",
    "ios": {
      "bundleIdentifier": "com.yourcompany.yourappname",
      "buildNumber": "1",
    },
    "android": {
      "package": "com.yourcompany.yourappname",
      "versionCode": 1,
    }
   }
 }

ビルドする

expo build:ios
expo build:android

でそれぞれビルドできます。

初回のビルドのときは、クレデンシャルなどを自分でアップロードするか、Expoに管理をおまかせするか、などを聞かれます。

僕はExpoにお任せするのをオススメします。 楽ちんなのでw
その場合、Apple IDやパスワードを聞かれます。

その後、Expoサーバー側でビルドが始まります。しばらく時間がかかります。

以下のようなメッセージが表示され、ビルド状況をモニタリングするURLが表示されます。
気になる場合はこのURLを覗いてみてもよいでしょう。

Building...
Build started, it may take a few minutes to complete.
You can monitor the build at https://expo.io/builds/07e11983-2649-4a93-a507-b9dc7a8927f8

そしてビルドが完成すると以下のように、ダウンロードURLが表示されます。

Successfully built standalone app: https://expo.io/artifacts/xxxxxx-xxxxxxxx-xxxxxxxx

このURLをブラウザで開くと、ipaファイルなりapkファイルをダウンロードできます。

ビルドをストアにアップロードする

androidの方はapkをgoogle play consoleのウェブサイト上でアップロードすればよいです。

iOSのほうはちょっと面倒で、ipaファイルをitune connectにアップロードするためには、
Application Loaderというアプリでアップロードします。

選択ボタンをクリックして先ほどのipaファイルを選ぶだけです。 f:id:wasan:20181023231536j:plain:w300

ビルドをアップロードできたら、あとは普通にitune connectで申請すればOKです!

更新ビルドを作るとき

app.jsonの

  • version
  • ios.buildNumber
  • android.versionCode

を変更して、あとは上記と同じ手順になります!

【Google Apps Script】Googleカレンダーから月間の稼働時間を集計する

こんにちは、maricuruのワダ(@takahi5)です。

今回はGoogle Apps Scriptネタです。

社内のグループウェアとしてG Suiteを使ってる会社は多いのではないでしょうか。
Google App Scriptを使うと、スプレッドシートやGoogleカレンダーをプログラムで操作できるので、定形作業を自動化したりできます。

手間のかかる事務作業を自動化するツールとか作るとメチャメチャ喜ばれますw

もちろん社員の労働効率もあがるので、会社としてもバンザイです。

f:id:wasan:20181103223544p:plain

解決したい課題

弊社では柔軟な働き方を推奨していて、子育て中のママさんが自宅でスキマ時間に作業をしてたりします。
また東京近郊だけでなく、関西で働いているスタッフもいます。

それらのメンバーの勤務時間は、Googleカレンダーに本人が入力する形で管理しています。
そして給与計算の際には、経理担当がGoogleカレンダーを手作業で数えています。

そこで、この手作業で数える作業をなんとかできないのか!?
というのが今回解決したい課題でした。

カレンダーを集計して稼働時間を出力する

そこで、この経理担当が人力でやってる作業をGoogle Apps Scriptを使って自動化しました。

いきなりコード全文です!
(実際の業務で使ってるのではなく簡潔にしたサンプルです)

要件はこんな感じです

  • 指定した複数のユーザーをまとめて取得
  • 特定タイトルの予定だけに絞って集計
  • 合計の稼働時間をサマリして表示

なげえ、、、

ではポイントを要約して解説します。

カレンダーの読み込み

var calendar = CalendarApp.getCalendarById('yamamoto@gmail.com');

のようにしてyamamoto@gmail.comのカレンダーを取得できます。
このときスクリプトの実行者はyamamoto@gmail.comのカレンダーを共有されている必要があります。

var events = calendar.getEvents(startDate,endDate); 

で対象期間のカレンダーイベントたちを取得します。

  for each(var evt in events){
   var title = evt.getTitle();
   var startTIme = evt.getStartTime();
   var endTIme = evt.getEndTime();
  }

それをforで回して各種情報を取得できます。

title, startTime...その他にも各種情報を取得できます。詳しくはコチラ↓

Class CalendarEvent  |  Apps Script  |  Google Developers

集計する

このサンプルでは、

evt.getTitle();

したものをチェックし、カレンダーの中から特定の予定名に絞っています。

また

evt.getEndTime() - evt.getStartTime() 

の差分で稼働時間を計算しています。

スプレッドシートに結果を出力

  var id = SpreadsheetApp.create('スプレッドシート名').getId();
  var spreadsheet = SpreadsheetApp.openById(id);

のようにしてspreadsheetインスタンスを取得できます。

var sheet = spreadsheet.insertSheet('summary');

summaryという名前のシートを挿入し、sheetインスタンスを取得します。

つぎに配列形式で持っているデータをガサっとsheetに書き込みます。

var array = [
  ['2018-10-26 9:00', '2018-10-26 14:00', '5', 'データ入力', 'yamamoto@gmail.com' ],
  ['2018-10-28 9:00', '2018-10-28 15:00', '6', 'データ入力', 'yamamoto@gmail.com' ],
  ['2018-10-29 9:00', '2018-10-29 14:00', '5', '文章校正',     'yamamoto@gmail.com' ]
]

のような配列があったとすると

  var rows = array.length;
  var cols = array[0].length;
  sheet.getRange(1,1,rows,cols).setValues(array);

これ一発で、この配列データががSheetに挿入されます。

まとめ

以上になります!

Google Apps Script用に覚えることは少しありますが、JavaScriptで書けるのはいいですね!
何かの参考になれば幸いです!

UGCサービスの設計 ~ 鶏が先か卵が先か~

こんにちは、maricuruのワダ(@takahi5)です。

僕はエンジニアの中でも、どちらかというとスペシャリストというよりはサービス寄りなタイプで、サービスの仕様とか考えるのも好きだったりします。

前職のDeNA時代には、特にコミュニティ系のサービス設計について多く学び、今もその経験を思い出しながらmaricuruを作っています。

そこで今回はサービス設計、とくにUGCサービスの初期の設計について考えてみたいと思います。
(あまりtechじゃないです...!)

f:id:wasan:20181101132903p:plain

はじめに直面する鶏卵問題

UGCのサービスといえば世の中には色々あります、YouTube、Instagram、最近だとTikTokなどなど、、、
列挙しだしたらキリがないですね。

そんな有名サービスを見て、自分でも作りたい!と思ったことは誰でもあるのではないでしょうか。


そんなときに

ユーザーを増やすにはコンテンツが必要だけど、コンテンツを増やすにはユーザーが必要....

という悩みにぶつかりがちです。

いわゆる、鶏が先か卵が先か問題です。


ここでよく

  • まずはキャンペーンでギフト券とか配ってコンテンツを増やそう!

  • いきなり有名クリエイターに投稿してもらってメジャー感を出そう!

とかを考えがちですが、これらはアンチパターンです。


この鶏卵問題は言い換えれば
投稿ユーザーが先か、閲覧ユーザーが先か?という問題になりますが、
答えは投稿ユーザーが先だと言われています。

maricuruでの実際の経験も踏まえながら、お話したいと思います!

まずは投稿型ユーザーにフォーカスする

YouTube、食べログ、クックパッド、今どき知らない人はいない程の有名サービスですが、
これらのサービスもローンチ当初は投稿ユーザーにフォーカスして成長してきたようです。

では、どのようにして投稿ユーザーを惹き付けてきたのでしょうか?

既存サービスの”かゆいところ”を解決する

YouTubeが世に出てきた当時、動画をネット上で共有する手段はあったものの、非常に手間がかかる作業でした。
そんな当時、YouTubeは圧倒的に簡単に動画を共有でき、それがもともと動画をホームページに掲載していた人たちに支持されたようです。

食べログやクックパッドも今となっては、レストランやレシピを探す”メディア”としての側面が強いですが、
創業当初は、グルメブログや料理ブログを書いてたユーザーが、ブログよりも書きやすいという理由から使い始めたのが原動力になっているようです。


これらの例に共通するのは、 なんらかの既存手段のかゆいところを解決しているという点です。


「いまはXXを使ってるんだけど、なんかココが使いにくい」
のような声が聞こえてきたらチャンスです。

その”かゆいところ”を解決することで、すでに発信欲の高いユーザーを惹き付けることができるかもしれません。

どんな業界にも、自分の情報をただただ発信したい!という発信欲の高いユーザーがいます。

そういったユーザーに”圧倒的な使いやすさ”を提供することで、初期の原動力を掴むことができます。
例えそのサービス内に見てくれる人が少なかろうが、この手のユーザーは気にせず発信してくれます。

一人でも楽しめる"ツール”として始める

先ほどの話は、すでに発信欲の高いユーザーを引っ張ってくる、という話でしたが、次は別のアプローチを考えてみます。

例としてinstagramを考えてみます。

今となっては超メジャーアプリのinstagram。
日々の写真を投稿するだけでなく、情報収集にも使われています。
今どきの女子はGoogle検索よりもinstagramでタグ検索するなんて言いますよね。


そんなinstagramもサービス開始当初を思い出してみると、
オシャレなフィルタ加工ができる”写真加工ツール”という印象でした。

あくまで"ツール”なので、instagram内にユーザーが多かろうが少なろうが、一人で楽しむことができます。

それが徐々に使う人が増えてくることで、コミュニティアプリとなり、今ではある意味メディアにもなってきました。

このように初期は一人でも楽しめるツールとしてスタートするのも、投稿ユーザーを集めるための有効な手段でしょう。

maricuruの場合は?

maricuruの立ち上げ当初、これらの先人の知恵はかなり意識しました。

maricuruのコンセプトは
「結婚式を終えた先輩花嫁(卒花)の経験を、これから結婚式を挙げる花嫁(プレ花)に伝える」
というものです。

具体的には、卒花が結婚式のレポート写真を投稿して、プレ花がそれを閲覧する、という形です。

そこでmaricuruでは、まず”卒花”にフォーカスしてサービスを設計することにしました。

卒花のかゆいところは?

ここ数年で花嫁さんのinstagram利用は爆発的に増えていて、
多くの花嫁さんがinstagramに結婚式専用アカウントを作り、結婚式準備や挙式当日のレポートを投稿していました。

そこでそのinstagramに何かかゆいところはないか?を探すために数十人の卒花さんにインタビューをしました。

そんな中である卒花さんの発言にヒントがありました


instagramは、、、

  • 投稿順に並ぶけど、ほんとは挙式→フラワーシャワー→披露宴、、、と時系列に並べたい
  • キャンペーン応募用の投稿など結婚式とは関係ない写真も混ざる
  • できれば挙式、披露宴、ハネムーンなどカテゴリごとに整理したい

という”instagramのかゆい所”っぽいものが見えてきました。


そこでmaricuruは

instagramの結婚式写真をインポートして整理できるアプリ

としてスタートしました。

結婚式のキラキラした思い出を整理できるアプリです。

なので”一人で楽しめるツール”という条件も満たしています。

このアプローチが功を奏し、結果的にリリース後3ヶ月で30000件を超える写真・動画が投稿されました。

アンチパターンについて

最後に、冒頭に書いたアンチパターンについて、思うところを書きたいと思います。
ちなみにこれらは過去に僕が踏んできたパターンでもあります(笑)

・ まずはキャンペーンでギフト券とか配ってコンテンツを増やそう!

ギフト券につられてきたユーザーは、ギフト券がなくなったら容易に去っていきます。
サービス開始当初から安易にそういったキャンペーンに頼るのは危険です。

僕のイメージでは、キャンペーンはRedBullみたいなものだと思っています。

たしかに翼は授けられるでしょう。
けど開始直後のサービスは、赤ちゃんのようなものです。 赤ちゃんにRedBullはやりすぎです。まずは母乳とかでちゃんと免疫をつけてあげましょう。

もちろん青年並みに成長したサービスで、キャンペーンを適切に使うのは賛成ですが。

サービス初期は、先にも書いたように”発信したくてたまらないユーザー"を原動力とするべきです。

・ いきなり有名クリエイターに投稿してもらってメジャー感を出そう!

カラオケに行って、初っ端に桑田佳祐が登場して歌うとします。
聴く人はもちろん満足するでしょう。
けど、その後に曲を入れるのは...入れにくくなるのではないでしょうか。

UGCでいきなり有名クリエイターを登用するのは、これに近いイメージだと思います。
投稿ユーザーにとってはハードルが上がりすぎて投稿しづらくなってしまいます。

初期はコンテンツのクオリティはそれほど重要ではありません。
むしろショボいくらいが良いとも聞きます。

まとめ

以上になります!

まとめると、
発信欲の高いユーザーを見つけて、その人たちをハッピーにしましょう!
ということですね。(雑なまとめw)

なんらかの参考になれば幸いです♪

【React Native】【Expo】ストアのレビュー誘導ダイアログを表示する

こんにちは、maricuruのワダ(@takahi5)です。

最近 結局、人生はアウトプットで決まる という本を読んだせいでアウトプット熱が高いです。
せめて1ヶ月くらいこの熱が保たれることを願います。

さて今回はストアのレビュー誘導ダイアログをExpoで実装してみた、というお話です。

レビュー誘導ダイアログとは?

「このアプリが気に入ったらレビューしてください!」

みたいなダイアログです。

昔はオレオレ実装でこのダイアログを出すことが出来たのですが、
iOS11からは、公式で用意されたSKStoreReviewControllerを使わないとリジェクト対象になります。

androidはオレオレ実装でも大丈夫です。

レビュー誘導をするきっかけ

ASOの向上を狙っています。

ストア検索の順位はレビュー数、レビュー★数に左右されるので、よいレビューがたくさん集まってるほど有利になります。

また、ユーザーがアプリを発見したあとも、よいレビューが多いほど安心してインストールできるので、結果インストール数も増えることでしょう。

まず仕様を考える

せっかくレビュー誘導のダイアログを出しても、悪評ばかりが蓄積しては意味がありません。

またダイアログが頻繁に表示されると、煩わしくてUXを低下させる恐れがあります。

そこで以下のような条件をもとに、ダイアログ表示のタイミングを判定するようにしました。

  • ある程度アプリを使い込んでいる(良いレビューをくれそう)
  • 前回のダイアログ表示から一定期間が空いた後 (頻繁に出るとウザい)
  • 何らかのアクションが一段落した後 (操作の途中に出ると煩わしい)

具体的には

  • 投稿を◯件以上しているユーザーで
  • 前回ダイアログ表示から◯日経過していて
  • 投稿が終わった後に表示

のような感じです。

レビュー誘導ダイアログの実装

ではExpoでレビュー誘導ダイアログを実装しましょう!

と言ってもExpoがStoreReviewというAPIを用意してくれているので、それを使えば楽ちんです。

まずapp.jsonにストアURLを入れておきましょう。
androidの方はストアに飛ばす仕様なのでURL必須です。

  # app.json
  "expo": {
    "ios": {
      "appStoreUrl": "https://itunes.apple.com/jp/app/id1320721074"
    },
    "android": {
      "playStoreUrl": "https://play.google.com/store/apps/details?id=com.maricuru"
    },
  }

レビュー誘導ダイアログを表示する

hasAction()でレビュー誘導ダイアログが表示できるかチェックして、
requestReview()でレビュー誘導ダイアログを表示します。

ちなみにレビュー誘導ダイアログの表示は、iOSの場合年間3回まで、ユーザーが設定でOFFに出来る、という制限があるため、それに引っかかった場合はrequestReview()を呼んでも表示されません。

  if (Expo.StoreReview.hasAction()) {
    Expo.StoreReview.requestReview();
  }

Expoクライアントで実行するとこんな感じで表示されました!
f:id:wasan:20181024162931p:plain:w300

Androidの場合は?

Androidの場合は、requestReview()を実行したら速攻でPlay Storeが開かれちゃいます...! (app.jsonで定義したplayStoreUrlが開かれます)

この唐突感はUX的にイマイチすぎます!

なのでAlertダイアログを挟むなどする方がよいと思います。

maricuruの場合はAlertダイアログで「レビューしてくれますか?」と尋ねた上でPlay Storeに飛ばすようにしました。

f:id:wasan:20181024221951p:plain:w300

全体の流れ(maricuruの場合)

結果的にこのようなフローチャートになります。

サーバーにレビュー誘導を表示すべきか問い合わせる

AndroidならAlertダイアログを挟む
iOSならふつうに表示

サーバーにレビュー誘導を表示した日時を保存

f:id:wasan:20181024222326p:plain:w400

といった感じです!

さてさて、効果が出るか楽しみです。
気長に待ちましょう🤗

LINEのLIFFを使ってみて分かったLIFFの可能性

さて1ヶ月ぶりの更新です。

この1ヶ月なにをやってたかと言うと...

オフィスを引っ越ししていました!

五反田の雑居ビルから、代官山のオフィスへ引っ越しました。

以前よりだいぶキレイなオフィスです。
個人的にはトイレがウォッシュレットになったのが涙モノに嬉しいです(T T)

f:id:wasan:20181020054001j:plain

また社名もダックリングズから、弊社のサービス名である"maricuru"に変更しました。

LIFFとは

さてtechと関係ないお話はそこそこにしておいて...
最近はLINEのLIFFという仕組みを使って、予約システムを作ったりしていました。

linecorp.com

新オフィスにはイベントスペースがあるのですが、そこで開催するイベントをLINE@上で予約するシステムになります。

LIFFとはLINE Front-end Framework の略で、要はLINE内でWebViewを動かすことができる仕組みになります。

LIFFの特徴

普通にURLでウェブページに飛ばせばよいのでは?と思っちゃいますが、以下のような特徴があります。

  • LINEアプリから出ずにシームレスに操作できる
  • Webページ内でのアクションをLINEのトーク画面にフィードバックしたりできる
  • ユーザーのLINEアカウント情報をウェブページで利用できる

事例としては、アンケート、予約などのフォーム入力する系が多いですが、中にはシューティングゲームなんかもありました。

LIFFアプリを作ってみる

ざっくり以下のような流れになります。

  1. アカウントの作成
  2. LIFFで表示したいウェブページを作る(https必須)
  3. そのページをLIFFに登録する

ではLIFFアプリを作る流れを、追ってみましょう。

アカウントの作成

まずはアカウントの作成ですが、このアカウントのルールがややこしく躓きました。

弊社で運用していたLINE@アカウントにLIFF機能を追加したのですが、LIFFを使うにはMessaging APIを有効にする必要があります。

ここで注意しないといけないのは、Massaging APIを有効にすると「1:1トーク」や「LINE@アプリ」が使えくなります。

LINE@のアカウントのユースケースは主に2パターンあるようです。

Messaging API 1:1トーク bot利用 主なユースケース LIFF利用
無効 小店舗などが顧客とのコミュニケーションに
有効 大企業が顧客対応に。(クロネコヤマトとか)

LIFFを使いたい場合、後者のMessaging API有効のパターンに設定する必要があります。

LIFFで表示するWebページの作成

何らかのWebページを公開しましょう。
httpsが必須になります。
herokuなどを利用してもOKです。herokuならデフォルトでhttpsですね。

早速herokuでサンプルのページを作ってみました。
f:id:wasan:20181020221032p:plain:w300

LIFF機能の細かい活用方法は後述します。

LIFFアプリの登録

続いてLIFFアプリを登録します。
まだ管理画面などは用意されていないようで、CLIからコマンドを叩いて登録しないといけません。

登録には先ほど作成したLINEアカウントの「アクセストークン」が必要になります。
LINE Developersコンソールのチャネル基本設定に記載されています。
f:id:wasan:20181020061256j:plain

先ほど作成したwebページのURLがhttps://hidden-ravine-56842.herokuapp.com/だとします。

以下のコマンドを叩くとLIFFアプリが登録されます。

curl -XPOST \
-H "Authorization: Bearer 【アクセストークン】" \
-H "Content-Type: application/json" \
-d '{
    "view": {
        "type": "tall",
        "url": "https://hidden-ravine-56842.herokuapp.com/"
    }
}' \
https://api.line.me/liff/v1/apps
項目 内容
type compact、tall、full でLIFF画面のサイズを指定します
url 表示したいWebページのURLです

実行すると、以下のようなレスポンスが返ってきます。

{"liffId":"160004001-Yt7Ef35HF"}

この場合

line://app/160004001-Yt7Ef35HF  

がこのLIFFアプリのURLになります。

このURLをトーク画面内で叩くことでLIFFアプリを開くことが出来ます。

早速そのURLをLINEトーク内で叩いてみましょう。

先ほどのWebページがLIFFで表示できました!

f:id:wasan:20181020221902p:plain:w300

LIFF SDKを使って色々する

ここまでだと単純にWebページをLINE内に表示したにすぎません。
LIFF SDKを利用することで LINEと連携した動作が色々可能になります。

LIFF SDKの初期化

headerなどでSDKを読み込んでおきましょう。

<script src="https://d.line-scdn.net/liff/1.0/sdk.js"></script>

liff.init() で初期化します。LIFF SDKの各種メソッドを実行する前に、まずこれを実行する必要があります。

liff.init();

トークにメッセージを送る

こんな感じでトーク画面にメッセージを送ることが出来ます。
注意点としては、このメッセージはユーザー側の方のメッセージになります。

liff.sendMessages([
{
  type: 'text',
  text: `予約が完了しました \n日時:${date} `
}])

プロフィールを取得する

こんな感じでLINEの表示名を取得できます。

liff.getProfile().then(function (profile) {
  window.alert(profile.displayName)
});

他にも、ユーザーIDや画像URLも取得できます。

LIFFウィンドウを閉じる

liff.closeWindwo()

APIの詳細はこちらにあります。

LIFF APIリファレンス

maricuruでのLIFFの活用

社内イベントスペースで開催するイベントの予約フォームをLIFFで表示しています。
LINEアプリ内で完結して操作できるのはよいUXかと思いました。

f:id:wasan:20181023223601p:plain:w300

LIFFの可能性

使ってみて感じたのは、まず

WebViewなので実装が簡単 、そして自由度が非常に高い、ということ。

今回は単純な予約フォームをrailsで組みましたが、ReactなりVueなりのフレームワークをゴリゴリ使ってよりインタラクティブなコンテンツをLINE内に組み込んだりも可能です。
また特にLIFF独自で覚えることも少ないので、過去のWeb開発のアセットがそのまま生きると思います。

逆に難点としてはデバッグがやりにくいことでしょうか、、
httpsの有効なサーバーにアップロードしないとLINE上での確認ができないので開発の効率はイマイチですね。