業務開発と個人開発で相乗効果を出すことができ、良い手応えを感じた話

はじめに

こんにちは。コミューン株式会社でソフトウェアエンジニアをしている板倉です。2022 年 5 月にコミューンに入社してから、モバイルアプリチームに所属しており、Flutter を用いたモバイルアプリ開発を担当しております。

Flutter はプライベートでも使用しており、個人でモバイルアプリを開発・リリースしております。

業務開発と個人開発で同じ技術(今回は Dynamic Links)を使うことにより相乗効果が出て、良い手応えを感じられることがあったため、この記事で紹介させていただければと思います。

コミューン株式会社では、コミュニティサクセスを支援するプラットフォーム「commmune」(アプリも同名称)を提供しています。 この「commmune」アプリは Firebase Dynamic Links を利用しています。

「commmune」アプリでは、主に以下のユースケースで Dynamic Links を利用しています。

  • 投稿通知メールや DM 通知メールに記載されたリンクをタップすると、該当の画面をアプリで開く(アプリが未インストールの場合はブラウザで開く)

上記のユースケースを実現するリンクの URL 構築は「commmune」のサーバサイドのシステム上で行われているため、アプリではそのリンク経由で起動された場合に渡される link というパラメータを元に遷移処理をさせれば良いことになります。

なお、Dynamic Links には link 以外にも多くのパラメータがあり、ストアや任意のWebページ(アプリの宣伝ページなど)を開くためのパラメータもあります。 firebase.google.com

実装について少しだけ触れると、Firebase Dynamic Links を利用するために、firebase_dynamic_links という Firebase 公式のパッケージを使用しています。

アプリ非起動時と起動時(フォアグラウンド/バックグラウンド時)でそれぞれ以下のように link パラメータを取得し、遷移処理を実行します。

// アプリ非起動時に Dynamic Links 経由で起動した場合
final initialLink = await FirebaseDynamicLinks.instance.getInitialLink();
final deepLink = initialLink?.link;
if (deepLink == null) {
    return;
}
// deepLink を元に遷移処理を実行する。
// フォアグラウンド/バックグラウンド時に Dynamic Links 経由で起動した場合
FirebaseDynamicLinks.instance.onLink.listen((dynamicLinkData) async {
    final Uri deepLink = dynamicLinkData.link;
    // deepLink を元に遷移処理を実行する。
}).onError((error) {
    debugPrint('onLink error ${error.message}', error);
});

これで「commmune」からの投稿通知メールや DM 通知メールに記載されたリンクをタップして、アプリを起動し、該当画面に遷移できるようになりました。 とても便利ですね。

業務開発で Dynamic Links に触れて便利さを実感したので、今度は個人で開発しているアプリにも Dynamic Links を入れてみたいと思いました。

そのアプリでやりたかったこと / やらなければいけないことは「commmune」アプリとは少し異なっていて、以下のようでした。

要件

  • 1.アプリが未インストールの場合、アプリのストアページを開いてアプリをインストールしてもらいたい
  • 2.「commmune」のようにサーバサイドのシステムがあるわけではないため、アプリ内のロジックでリンクを生成する必要がある
  • 3.作成したリンクを Twitter などでシェアさせたい

いずれの要件も単純でそれぞれ

  • 1.パラメータの aflifl を指定しなければ良い
  • 2.リンクの生成処理をアプリ内のロジックで実装する
  • 3.シェアする文面に生成したリンクを含める

で実現は可能です。

ただ、要件 3 には隠れた要件がありました。以下のようなものです。

  • 3-1.リンクの URL を長い文字列にしたくない
  • 3-2.指定するパラメータは可能であれば隠蔽したい

要件 3-1 は主に Twitter でのシェアを意識し、140 文字制限を考慮したものでした。
(後に気づいたのですが、Twitter には 140 文字の制限はあるものの、URL は 22 〜 24 文字でカウントされるため、文字数制限のために URL を短縮する必要はありませんでした。)

要件 3-2 は内部の構造などを推察されてしまう可能性があるため、可能な限りで隠蔽したいと考えておりました。調べてみると、Firebase にはショートリンクを生成する REST API が提供されていることがわかり、これを利用することにしました。

firebase.google.com

追記

Firebase Dynamic Links ショートリンク API ですが、
firebase_dynamic_links パッケージ内にも buildShortLink という関数があり、これがこの REST API と同機能のようでした。同パッケージを導入しているならこの関数を利用した方がシンプルにコードが書けて良さそうです。
(本記事の社内レビュー中に社内メンバーから指摘いただいて気づきました。とてもありがたいなと思うと共に、情報をアウトプットする良さと効果を改めて感じました。)

firebase.google.com

ショートリンク生成の実装例(REST API 使用)

Firebase Dynamic Links ショートリンク API を呼び出して URL を取得するサンプルコードは以下になります。

final url =
    "https://firebasedynamiclinks.googleapis.com/v1/shortLinks?key=<YOUR-API-KEY>";
final uri = Uri.parse(url);
final body = json.encode({
  "dynamicLinkInfo": {
    "domainUriPrefix": "https://xxxxx.page.link",
    "link": "https://xxxxx.yyy?sampleParam=1234",
    "androidInfo": {
      "androidPackageName": "<YOUR-PACKAGE-NAME>",
    },
    "iosInfo": {
      "iosBundleId": "<YOUR-BUNDLE-ID>",
      "iosAppStoreId": "<YOUR-APP-STORE-ID>",
    },
  },
  "suffix": {
    "option": "SHORT",
  }
});

final response = await http.post(
  uri,
  headers: {"Content-Type": "application/json"},
  body: body,
);

String? shortLink;
if (response.statusCode == 200) {
  final jsonResponse =
      convert.jsonDecode(response.body) as Map<String, dynamic>;
  // shortLink に https://xxxxx.page.link/PkHv のような短い URL が入っている。
  shortLink = jsonResponse["shortLink"] as String;  
}

なお、上記は http というパッケージを使用する前提のコードになっています。

今後「commmune」アプリで同様の要件が発生した際に使用できそうだなと思いました。

動作確認を通じて得られた気づき

「Dynamic Links はエミュレータ / シミュレータでは動作しないため、実機での確認が必要」であるため、業務開発を行っていた際には毎回 Android / iOS 実機を使用して動作確認をしていました。

しかし、個人開発で色々と調べていた際に以下の記事を発見しました。 zenn.dev

adb (Android) や xcrun (iOS) コマンドを使用すれば、Dynamic Links の動作確認がエミュレータ / シミュレータでも行えるということがわかりました。

例えば、Android エミュレータで動作確認する際のコマンドは以下のようになります。

adb -e shell 'am start -W -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "https://xxxxx.page.link/?apn=<YOUR-PACKAGE-NAME>&afl=https://xxxxx.yyy?sampleParam=1234&ibi=<YOUR-BUNDLE-ID>&ifl=https://xxxxx.yyy?sampleParam=1234&link=https%3A%2F%2Fxxxxx.yyy%3FsampleParam%3D1234"'

社内での知見共有

コミューンのモバイルアプリチームでは不定期で Flutter 関連技術の知見をシェアする勉強会をしています。 そこで、今回個人開発で得られた情報2点をさっそくドキュメント化してシェアしました。

  • Firebase Dynamic Links ショートリンク API
  • adb / xcrun コマンドでの Dynamic Links の動作確認方法

特に adb / xcrun コマンドの件は「commmune」アプリの開発にもすぐに使え、業務効率化につながるような内容でチーム内でも好感触を得られました。

個人的にも業務開発と個人開発で双方のフィードバックを行うことができ、相乗効果が得られたと感じています。

まとめ

今回、業務開発と個人開発で同じ技術(Dynamic Links)を使ってみて、以下2点の気づきがありました。

  • それぞれで要件が異なるため、新しいやり方・技術(今回は Firebase Dynamic Links ショートリンク API)を知れることがある
  • 一方の開発で気づかなかった点(今回は adb / xcrun コマンド)でも、もう一方の開発に取り組む過程で気づくことがある

業務開発で使用した技術を個人開発でも利用、
個人開発で気づいた内容を業務開発にもフィードバック
することによって、双方の開発に良い影響を与えることを実感しました。

今後も相乗効果を得られるように、業務開発にも個人開発にも取り組んでいきたいなと考えております。

おわりに

コミューンではエンジニアを募集中です!少しでも興味のある方は気軽にカジュアル面談に申し込んでみてください!

commmune-careers.studio.site