‘Flutter’ タグのアーカイブ

aikawa

VirtualBoxのUbuntuにFlutter開発環境を構築

FlutterをWindowsで使っていて、プロジェクトにshellコマンドとか絡んで来ると、結構上手く行かない事が。
CygwinとかWSLを使っても、駄目な時は本当に駄目というか、それ専用で動かす労力が必要と考えると(修正しても後で動かなくなる可能性が・・・)。

そんなわけで、shellがそのまま動かせるLinux+Flutter開発環境が欲しくなったので、ちょっとUbuntu上に作ってみます。

Ubuntuインストール・・・は飛ばして、Flutterから

VirtualBoxにUbuntuのインストールとVirtualBox Guest Additionのインストールは、特に苦労する事は無いので省略。

LinuxへのFlutterインストールは下記を参考に。
https://docs.flutter.dev/get-started/install/linux/android





1. 次のパッケージをインストール

sudo apt-get update -y && sudo apt-get upgrade -y;
sudo apt-get install -y curl git unzip xz-utils zip libglu1-mesa

2. AndroidStudio用に以下をインストール

sudo apt-get install libc6:amd64 libstdc++6:amd64 lib32z1 libbz2-1.0:amd64

Android Studio

https://developer.android.com/studio/install?hl=ja#64bit-libs
こちらで64bit版は追加パッケージが必要となっていますが、殆どが見つからない状況なので、自分のは64bit版じゃないのかと思ったけどやはり64bit版だったので、無いものは無視しました。


UbuntuのFirefoxで以下にアクセスして、Linux版のAndroid Studioをダウンロード。
https://developer.android.com/studio?hl=ja





後はHomeのopt/以下に展開して起動。

tar xzf android-studio-*-linux.tar.gz
mkdir ~/opt
mv android-studio ~/opt/
cd
./opt/android-studio/bin/studio

起動後は、画面に従い設定を進めて行きますが、特に変更はなくデフォルトのままで良かったです。

以下のようにプロジェクトを選択する画面まで行ったら完了。

Visual Studio CodeとFlutter

同じようにUbuntuのFirefoxで https://code.visualstudio.com/download からdebインストーラをダウンロード。
クリックするとインストール画面になるので、Installを選択すればインストールされます。

起動後に、extensionでFlutterやDartの拡張機能を入れておきます。



Flutter本体はVisual Studio Code内からインストール出来るので、それを使います。
Ctrl+Shift+Pで上部に入力フォームが出るので、flutterと打つとプロジェクトを開始前にインストールが始まります。
展開先のフォルダ指定を聞かれるので、/home/vboxuser/opt 辺りを展開先に選び、右上ボタンを押します。
インストールは結構時間が掛かります。

終了後、flutter doctorを実施して、一応動くか確認。後でOKでない部分を潰して行きます。

~/opt/flutter/bin/flutter doctor

ついでに環境変数PATHにflutterを追加します(.profile辺りに)。

export PATH="$HOME/opt/flutter/bin:$PATH"

Android SDK Manager

ブラウザでダウンロード先を探す必要はなく、Android Studioからインストールします。
右上の…が縦になっているのをクリックして、下にあるSDK Managerを開きます。







SDK Toolsタブへ移動して、Android SDK Command-line ToolsとAndroid SDK Platform-Toolsを(チェックされてなければ)チェックしたら右下のApplyが押せるようになるので、Applyを押すとインストールが始まります。

~/Android/Sdk/cmdline-tools/latest/bin/sdkmanager が出来ているのを確認したら、環境変数ANDROID_HOMEを追加します。

export ANDROID_HOME=/home/vboxuser/Android/Sdk/

Google Chrome

FirefoxでChromeで検索してダウンロードしたら、インストールします。それだけ。

flutter doctorの不足分

まずはライセンスに合意します。

flutter doctor --android-licenses

次に、flutter doctorで不足となっているパッケージを入れます。今回はこんな感じでした。

sudo apt install clang cmake ninja-build pkg-config libgtk-3-dev

実はJDKも必要

これで一応Flutterは動くんですが、AndroidをビルドするためにはJDKをインストールする必要が有ります。それにFlutterの古いプロジェクトやライブラリを使っていると、JDKの古いバージョンでないとビルド出来ないとかがあるので、17と21を入れておきました。

sudo apt install openjdk-21-jdk
sudo apt install openjdk-17-jdk

環境変数JAVA_HOMEを追加します。17の場合は次のような感じ。

echo export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64/

最終的な環境変数

最終的な環境変数を追加した~/.profileファイルは以下のようになると思います。

export PATH="$HOME/opt/flutter/bin:$PATH"
export ANDROID_HOME=/home/vboxuser/Android/Sdk/
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64/

Android端末をFlutterでデバッグに使うために

最初はAndroid Studioのエミュレータを動かそうとしたんですが、動いたものの途中でVMがエラーを吐いてしまったので、使えないと断念しました。

一応そのためにやった事として。
VM内でエミュレータを動かすには、VMがネステッドVT-x/AMD-Vを有効化している必要が有りますが、デフォルトだとチェックが出来ない状態でした。
自分の場合は、コア分離のメモリ整合性のオフ、リアルタイムスキャンのオフでチェックが出来るようになり、起動後のVMがミドリガメ状態にならなくなりました(右から3番目のアイコン、キーボード・マウスの次のVが、緑でなく青になっている)。

デバッグ用Android端末は実機で

じゃあもう実際の端末を使うしかなくなっちゃったよ、という事で、VMからUSBを認識する手順です。
Android端末は、USBでホストのWindowsに接続しておきます。
VM停止状態で、仮想マシンを選択>右クリックで設定を開き、USBタブへ移動。
USB3.0を選択して、USBデバイスフィルター右のアイコンで、上から二番目の+が付いてる奴をクリックすると、選択肢が出て来るので、Android端末の名前が出ているのをクリックすると、一覧に追加されます。

この状態で起動して、ゲストOSウィンドウ右下のUSBアイコンを右クリックして、対象のデバイスをクリックすると、チェックが付きます。

VSCodeでFlutterプロジェクトを開き右下のDeviceをクリックすると、一覧に端末が出るので選択します。これでデバッグにAndroid端末を使えるようになりました。

ただ、USBを認識出来ない、チェック時にUSBデバイスへの接続に失敗してしまう時も有るので、そんな時はWi-Fiで繋げます(その前にAndroid再起動するとかは試しますが)。

Android端末をWifi接続

・Android Studioを開き、Flutterプロジェクトを開きます。
・右アイコンのAndroid君がいる奴を選択し、Device Managerを開きます。
・WiFiアイコンを選択するとQRコードが出ます。
・Android端末で開発者向けオプションのワイヤレスデバッグをタップ(有効な状態で)すると、QRコードによるデバイスのペア設定が出るので、出ているQRコードを読み取ります。

その後失敗したとか出ましたが、何か追加されていたので、VSCodeでも選べるようになっていました。
こっちの接続は(wireless)と付いてます。

あとはサンプルプロジェクト等で、デバッグを開始して端末にアプリが表示されればOKです。

suganuma

FlutterのWindowsアプリでIMEの切り替え

FlutterのWindowsアプリで、TextFieldフォーカス時にIMEをオン/オフ切り替える機能を実装してみました。
最初、TextFieldのTextInputTypeを使ってキーボードをphoneやemailAddressに指定すればIMEが切り替わるのでは、と思い試しましたが、切り替わりませんでした。
プラグインでIMEを切り替えられるものを探しましたが見つからなかったので、以下を参考にwin32 APIを呼び出す方法で実装しました。
https://docs.flutter.dev/development/platform-integration/platform-channels#step-5-add-a-windows-platform-specific-implementation

上記に書かれてるように、まずwindows/runner/flutter_window.cppの#include "flutter_window.h"の後に以下を追記します。

#include <flutter/event_channel.h>
#include <flutter/event_sink.h>
#include <flutter/event_stream_handler_functions.h>
#include <flutter/method_channel.h>
#include <flutter/standard_method_codec.h>
#include <windows.h>

#include <memory>
dllを呼び出すため以下をflutter_window.cppに記述します。

#pragma comment(lib, "imm32.lib")
#pragma comment(lib, "user32.lib")
FlutterWindow::OnCreate
メソッドを編集し、チャンネル名 hoge.flutter.dev/imeに結びついた flutter::MethodChannelを作成します。

bool FlutterWindow::OnCreate() {
// ...

flutter::MethodChannel<> channel(
flutter_controller_->engine()->messenger(), "hoge.flutter.dev/ime",
&flutter::StandardMethodCodec::GetInstance());
channel.SetMethodCallHandler(
[](const flutter::MethodCall<>& call,
std::unique_ptr<flutter::MethodResult<>> result) {

HWND hwnd = GetForegroundWindow();
HIMC himc = ImmGetContext(hwnd);
if (call.method_name() == "imeOn") {
ImmSetOpenStatus(himc, true);
} else {
ImmSetOpenStatus(himc, false);
}
ImmReleaseContext(hwnd, himc);
result->Success();

});
return true;
}

次にFlutter側でチャネルを介してメッセージを送信するようにします。
以下のWidgetを作成します。

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class ToggleIme extends StatelessWidget {
final Widget child;
final bool enable;
const ToggleIme({super.key, required this.child, required this.enable });
static const platform = MethodChannel('hoge.flutter.dev/ime');

@override
Widget build(BuildContext context) {
return Focus(
skipTraversal: true,
child: child,
onFocusChange: (hasFocus) {
if (hasFocus) {
if (enable) {
platform.invokeMethod('imeOn');
} else {
platform.invokeMethod('imeOff');
}
}
} ,
);
}
}
TextFieldを以下のような感じでラップします。

ToggleIme(
enable: false,
child: TextField(),
)
これでTextFieldフォーカス時にIMEがオフになるようになりました。