2024.12.19
システムの穴を運用でカバーしようとしてミス多発… バグが大量発生、決算が合わない状態から業務効率化を実現するまで
Flutter に iOS 14 などの新機能を取り込むには(全1記事)
リンクをコピー
記事をブックマーク
垰尚太朗氏:まず自己紹介からすると、CL事業部にiOSエンジニアとして所属しているTao Shotaroです。今回は『FlutterにiOS14などの新機能を取り込むには by iOSエンジニア』というタイトルで話していきたいと思います。少しiOSについての話が多いですが、ご了承ください。内容も簡単なのでサラッと見ていただけると幸いです。
それでは課題から話します。React Native、Kotlin Multiplatform、Flutterのようなネイティブコードを使わずにアプリ開発ができる言語を人に勧めると、「え、UIってどうなるの?」とか「機能が制限されそう」とか「iOS・Androidに出る新しい機能も取り入れたい」とかの反応が返ってくるのが多いので、今回はiOS・Androidの新しい機能も取り入れるという点について、実際どのように対応していくのかを紹介したいと思います。
まずFlutterには、MethodChannelというクライアント側とプラットフォーム側が通信するためのメソッドが用意されています。Flutter側はこのMethodChannelを利用して、プラットフォームであるiOSやAndroid側にメッセージを送ります。
するとiOS側はFlutterMethodChannel、Android側はMethodChannelというクラスがそのメッセージを受け取り、必要なデータを返します。
このMethodChannelを利用すると、比較的簡単にネイティブのコードを呼び出せます。またデータを定期的に流す場合は、MethodChannelのストリーム版であるEventChannelというメソッドを利用できます。
デバイスのバージョンや名前などの情報を取得したいときはMethodChannel、ユーザーの位置情報を定期的に取得したい場合はEventChannelなど、必要に応じて使い分けるのがいいです。
データの受け渡しですが、MessageCodecに準拠したエンコーダによってバイトデータに変換されます。MethodChannelとEventChannelは標準でStandardMessageCodecというエンコーダを利用しています。
このStandardMessageCodecが対応している型はここに表示してあるとおりで、null、Boolean、Int、Double、String、List、Mapです。独自のデータ型を使ってやりとりしたい場合は、MessageCodecに準拠した独自のエンコーダも用意できます。
次にMethodChannelとEventChannelの使い方です。使い方は簡単で、まずアプリケーションを用意して、プラットフォーム側のAPIを利用したい画面、もしくはウィジェットのStateでMethodChannelを宣言します。このとき、チャンネルの名前はFlutter側とiOS側、Android側で統一しなければいけません。
そして、先ほど宣言したチャンネルを使ってプラットフォーム側にメッセージを送ります。今回の場合は、getDeviceInfoです。すると、このinvokeMethodが非同期で結果を返します。今回はMapを返すように実装しているので、dynamicMapにキャストしています。
dynamicタイプのMapが返ってくるので、それを_deviceInfoで保持しています。stateの中に入っている_deviceInfoですね。最後にこの関数はinit stateで呼んでいます。
iOS側の実装は先ほどの同じ名前を使って、FlutterMethodChannelを宣言します。今回はdeviceinfoと設定しています。
このときアプリ上で動いているFlutterエンジンが1つとは限らないので、windowから先ほど書いたFlutter側のコードが動いているFlutterViewControllerを取得して、channelに設定しま す。このbinaryMessengerというところです。
このdeviceInfoChannelを使って、メッセージのハンドリングを行います。このとき気をつけないといけないことは、このメソッドはメインスレッドで実行されているので、非同期処理をここで行う場合は別スレッドに移動しないといけないということです。
今回の場合はdeviceInfoのDictionary型を返しました。これで実行すると、きちんとiOSの情報が表示されるのですが、すみません、実行結果の画像を忘れてしまいました(笑)。今回はiOSだけの紹介になりましたが、Androidでも受け渡すデータを揃えれば同じ方法で実装できます。
先ほどの実装を1つのパッケージにしてプラグインとして公開しているのが、公式から出ているdevice_infoというライブラリです。このライブラリを見ると、Objective-Cで書かれているものの、ほとんど同じような実装をしていることがわかります。
ここの部分でFlutterMethodChannelを宣言して、handleMethodCallという関数でイベントのハンドリングを行なっています。
shared_preferencesというUser Defaultの管理などに使われるライブラリも同じで、内部でFlutterMethodChannelを用意してgetAllやsteBoolやsetIntなどのイベントをハンドリングしています。
まとめです。プラットフォーム側のAPIを利用したい場合は、MethodChannelやEventChannelを利用することでデータのやりとりができることがわかりました。
コードの半分ほどは、プラットフォーム側のネイティブコードを書いているのですが、通常のアプリで使用するような位置情報の取得や、デバイス情報の取得や、ローカルステージのデータの保存、ブラウザの表示など、基本的なネイティブAPIはすでにライブラリとして、公式からもしくは有志によってオープンソースとして公開されています。
ライブラリがないときや、すでに自分がiOS、Androidのライブラリとして公開しているものをFlutterで使いたいときは、このMethodChannelやEventChannelを利用することで使えます。
今回は『iOS14の新機能を取り込むには』というお題だったので、続いて「App Clips」と「Widgets」について話していきたいと思います。
MethodChannelとEventChannelは、ある特定のAPIを利用したいときに使用できるのですが、App ClipsやWidgetsのようにメインプロジェクトとはターゲットが異なり、起動するタイミングも違って、別プロジェクトのような機能が追加されたときはどのように対応したらいいでしょうか。
やり方は2つあります。基本的にネイティブですべて実装して、データのやりとりだけMethodChannelやEventChannelを利用する方法と、メインアプリとは別にFlutterEngineやFlutterViewControllerを用意してFlutterで実装する方法です。
後者のFlutterEngineやFlutterViewControllerを用意してFlutterで実装する方法は少し複雑なので、順番に解説していきたいと思います。
まずFlutterの仕組みを簡単に説明します。FlutterのアプリケーションのコアがFlutterEngineです。真ん中にある青いやつですね。これはC++で書かれていて、画面の描画やレイアウトの計算など、ネットワークに関する低レイヤーの実装がされています。
そして、その上に実装されているのが、Dart UIというフレームワークです。FlutterのC++のコードをラップしてくれます。Flutterでアプリを作る場合、基本的にはこのフレームワークか、この上に存在するWidgetsやMaterialなどのUIフレームワークを使用します。
FlutterEngineの下にはネイティブのコードが実装されていて、先ほどのMethodChannelで定義したネイティブのコードは、このPlatform-SpecificのNative Pluginsにあたります。これはFlutterのドキュメントに詳しく説明が書かれているので、勉強したい方は読んでみるといいと思います。
App Clipsがどういうものかというと、本体のアプリとは別の必要最低限の部分だけを取ったアプリです。
App Clipsは10MBの制限があるので、FlutterEngineをこの中で実装するのは難しいと言われています。ただ、Flutterの開発者のがんばりによって、今は10.6MBまで下げられたので、もう少ししたらApp Clips上でFlutterEngineを動かせるんじゃないかなと言われています。
ローカルで試すだけであれば10MBを超えても大丈夫みたいなので、実際にやり方を紹介していきたいと思います。けっこう簡単で、まずApp Clipsのターゲットを作成して、そこの中でFlutterEngineとFlutterViewControllerを宣言して、FlutterViewControllerを表示するだけです。
FlutterViewControllerはFlutterEngineを動かしている画面です。Androidにも同じようなものがあって、確かFlutterViewがその役割を担っています。
このようにFlutterEngineとFlutterViewControllerを宣言します。Entrypointとして初期画面を指定することもできるので、App Clips専用の画面を用意して、そこに流すこともできます。
App Clipsを実装するときは、FlutterのフレームワークをApp Clipsのターゲットへ追加したり、ビルドの設定をしたりなど細かい設定が必要なんですが、実は公式のガイドが存在していて、それに従って設定すれば実行できるので、それを見るといいと思います。
これは先ほど言ったとおり、10MBを超えていて、まだ実験段階です。実際にAppStoreで公開できている事例は見たことがありません。仮に10MBの制限をクリアできなかった場合、選択肢の1つ目の、基本的にネイティブで実装してデータのやりとりだけMethodChannelやEventChannelを利用する方法を取るしかなさそうです。
続いてiOS14から追加されたWidgetsですが、基本的には先ほどと同じでネイティブで実装する方法と、メインアプリとは別にFlutterEngineを用意する方法があります。後者のFlutterEngineを利用する方法は、UIをレンダリングするのにメモリがたくさん必要で、確かシミュレーターでは動くのですが、実機では動かないみたいな制限があるので、現実的ではありません。
現実的な方法として、データはshared_preferencesというUserDefaultのライブラリを使ってFlutter側から共有して、Widgetsでそのデータを取得して画面に表示するのが現実的な方法かなと思います。
MethodChannelを利用して、Widgetsの更新タイミングをFlutter側から呼び出すこともできます。ちなみにそのWidgetsの更新タイミングをFlutter側から呼び出すライブラリは、すでに有志によってオープンソースで公開されています。Flutter界隈が活発なのはすごくありがたいですね。
最後です。少し短かったのですが今回はMethodChannelとEventChannelの使い方と、別ターゲットでのFlutterEngineの動かし方について紹介しました。MethodChannelの使い方を理解しておくと、どうしてもネイティブのAPIを利用しないといけないときも幅広い対応を行えるので、ぜひ試してみてください。以上で終わります。ありがとうございました。
2024.12.20
日本の約10倍がん患者が殺到し、病院はキャパオーバー ジャパンハートが描く医療の未来と、カンボジアに新病院を作る理由
2024.12.19
12万通りの「資格の組み合わせ」の中で厳選された60の項目 532の資格を持つ林雄次氏の新刊『資格のかけ算』の見所
2024.12.16
32歳で成績最下位から1年でトップ営業になれた理由 売るテクニックよりも大事な「あり方」
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
PR | 2024.12.20
モンスター化したExcelが、ある日突然崩壊 昭和のガス工事会社を生まれ変わらせた、起死回生のノーコード活用術
2024.12.12
会議で発言しやすくなる「心理的安全性」を高めるには ファシリテーションがうまい人の3つの条件
2024.12.18
「社長以外みんな儲かる給与設計」にした理由 経営者たちが語る、優秀な人材集め・会社を発展させるためのヒント
2024.12.17
面接で「後輩を指導できなさそう」と思われる人の伝え方 歳を重ねるほど重視される経験の「ノウハウ化」
2024.12.13
ファシリテーターは「しゃべらないほうがいい」理由 入山章栄氏が語る、心理的安全性の高い場を作るポイント
2024.12.10
メールのラリー回数でわかる「評価されない人」の特徴 職場での評価を下げる行動5選
Climbers Startup JAPAN EXPO 2024 - 秋 -
2024.11.20 - 2024.11.21
『主体的なキャリア形成』を考える~資格のかけ算について〜
2024.12.07 - 2024.12.07
Startup CTO of the year 2024
2024.11.19 - 2024.11.19
社員の力を引き出す経営戦略〜ひとり一人が自ら成長する組織づくり〜
2024.11.20 - 2024.11.20
「確率思考」で未来を見通す 事業を成功に導く意思決定 ~エビデンス・ベースド・マーケティング思考の調査分析で事業に有効な予測手法とは~
2024.11.05 - 2024.11.05