
flutter開発:platform間の呼び出しとパラメーターについて
-
2023年5月22日
はじめに
こんにちは。エンジニアのCです。
今回はflutter開発において、platform間の呼び出しについて軽く紹介したいと思います。
flutterは、Googleによって開発されたオープンソースのアプリケーション開発フレームワークです。Dart言語を使用しており、cross-platformをサポートしていて高品質で高い生産性を提供している開発環境ではありますが、詳しい情報を探す場合、検索してもあまり出てこないなど「情報が足りないな〜」と思う場面が多くあると思います。
今回はflutterを使ったツールの開発となりますが、その中でplatform間の呼び出し方法とパラメーターの渡し方について皆さんに共有したいと思います。
ツールのプロセスの流れ
→ Adobe Photoshopの実行
→ Photoshop jsxファイルの実行
→ ファイル書き出し
→ 書き出されたイメージでatlasイメージとmetaファイルを生成
1. Adobe Photoshopの実行
- Macはshellを使ってApple Scriptを実行する
- WindowsはMethod Channelを利用し、COMオブジェクトを使って起動する
if (Platform.isMacOS) {
//macos call
var arguments = [
'$workfolder/assets/libs/Exporter.scptd',
'$workfolder/assets',
sourcepath
];
final result = await Process.run('osascript', arguments);
return result.exitCode;
} else if (Platform.isWindows) {
//windows call
MethodChannel channel = const MethodChannel('script_runner_channel');
final result = await channel.invokeMethod('runWindowsJavaScript', {'workfolder': workfolder, 'sourcepath': sourcepath});
return 0;
} else {
//not supported platform
throw 'not supported platform.';
}
※Macの場合はshell起動でPhotoshopを起動しようとすると何も起きないと思いますが、これはセキュリティ的にデフォルトで作ったflutterプロジェクトの設定がOffになっているからです。こちらを解決するには下記の設定を変更する必要があります。
※Windowsの場合はMethod ChannelでCOMオブジェクトを実行することになりますが、パラメーターを渡すためには下記のように受け取る指定をする必要があります。
const static std::string channel_name("script_runner_channel");
auto channel =
std::make_unique<flutter::MethodChannel<>>(
flutter_instance->messenger(), channel_name,
&flutter::StandardMethodCodec::GetInstance());
channel->SetMethodCallHandler(
[](const flutter::MethodCall<>& call, std::unique_ptr<flutter::MethodResult<>> result) {
flutter::EncodableMap arguments = std::get(*call.arguments());
if (call.method_name().compare("runWindowsJavaScript") == 0) {
// do whatever you want
std::string workfolder = std::get(arguments[flutter::EncodableValue("workfolder")]);
std::string sourcepath = std::get(arguments[flutter::EncodableValue("sourcepath")]);
std::cout << "------- runWindowsJavaScript -------" << std::endl;
std::cout << "workfolder : " << workfolder << std::endl;
std::cout << "sourcepath : " << sourcepath << std::endl; runWindowsJavaScript(workfolder, sourcepath); result->Success("pass result here");
}
else {
result->NotImplemented();
}
});
パラメーターによっては受け取る側の実装を変える必要があります。
2.Photoshopでの実行が完了するとAtlasイメージを作るためにC++コードを実行
- PluginでFlutterからC++のコードを呼び出す
Dart側のcall
if (Platform.isMacOS) {
//macos call
var arguments = [
'$workfolder/assets/libs/Exporter.scptd',
'$workfolder/assets',
sourcepath
];
final result = await Process.run('osascript', arguments);
return result.exitCode;
} else if (Platform.isWindows) {
//windows call
MethodChannel channel = const MethodChannel('script_runner_channel');
final result = await channel.invokeMethod('runWindowsJavaScript', {'workfolder': workfolder, 'sourcepath': sourcepath});
return 0;
} else {
//not supported platform
throw 'not supported platform.';
}
C++側の実装
#if defined(_WIN32) || defined(_WIN64)
# define DART_EXPORT extern "C" __declspec(dllexport)
#else
# define DART_EXPORT extern "C" __attribute__((visibility("default"))) __attribute__((used))
#endif
DART_EXPORT
int32_t calcAtlasImage(const char *path) {
std::cout << "calcAtlasImage : " << std::string(path) << std::endl;
return 0;
}
※Macでは、PluginをXCodeプロジェクトに追加する必要があります。またWindowsでは、dllとして作成し、ライブラリとして読み込む必要があります。
まとめ
Dart言語だけを使う場合は呼び出しやパラメーターについてあまり悩む必要がありませんが、platform間でDart言語から呼び出したい、パラメーターを渡したい、となるとかなり面倒な作業が発生します。またflutterはcross-platformをサポートする開発環境ではありながらも詳しい情報を調べようとするとあまり情報がない場合があります。 また、Dartを使ってplatform間の関数を呼び出すのはかなりのoverheadがあり負荷が高くなると思います。可能な限り纏めた形にしたものを呼び出すか、本当に必要なところだけにした方が良いかと思いました。
ココネでは一緒に働く仲間を募集中です。
ご興味のある方は、ぜひこちらの採用特設サイトをご覧ください。