UbuntuでFlutter環境構築(2020年11月版) Android編

Posted by 雅楽斎 on Thursday, November 19, 2020

TOC

とにかくインターネットからダウンロードしまくるのを(不完全ながら)緩和する

Googleの開発環境は概ねそうなっている気がしますが、開発環境の構築でインストールした後に再びインターネットから数百MBのダウンロードが必要で、複数台の環境構築をする場合に大量のインターネット接続が必要になる事態に陥ります。1

なので、今回Ubuntu上でFlutter環境を構築するにあたって少しだけ通信量の削減を意識した手順で開発環境を構築します。

作業は以下の手順で実施します。確認環境はUbuntu MATE 20.04(amd64)です。

  • Flutterの環境構築(前編) - snapパッケージでインストール
  • Android SDKのインストール
  • Flutterの環境構築(後編) - flutter doctorで妥協できる線まで持っていく
  • IntelliJ IDEA Communityのインストール、設定
  • サンプルの動作

それぞれの設定値やインストール方法は以下の通りです。

プロダクト・
環境変数等
インストール方法・
設定値
備考
Fluttersnapパッケージsnapパッケージインストール後に500MBダウンロードが必要
Android SDKsnapパッケージsnapパッケージインストール後に別途パッケージをダウンロードしてインストールが必要
IntelliJ IDEA
Community Edition
snapパッケージ
環境変数
ANDROID_SDK_ROOT
~/AndroidSDKAndroidSDKのsnapパッケージで使われるパス。Flutter実行時、IntelliJ IDEAの設定時に参照する
Flutter SDKのパス~/snap/flutter/common/flutterIntelliJ IDEAのFlutterプラグインで指定

DartはFlutter 1.19.0以降は含まれるようになったことからDartの環境構築はしていませんが、私の場合別途インストールしてあるdartを参照しています(後述)。

snapパッケージのインストール時に事前にダウンロードするか否か

snapパッケージをインストールする場合、直接snap storeからインストールするとパッケージの更新が強制されるため、個人的には(特に大きいパッケージの場合)事前にダウンロードをしています。この場合2つのメリットがあります。

  • 意図しないタイミングでのパッケージ更新による通信量を抑えられること
  • アーキテクチャが共通であればパッケージファイルを使い回せること

詳細は以前まとめたものがありますので、参照いただければと思います。

Snapを使用する

Flutterのインストール

Flutterはsnapパッケージが公式に提供されているのでこれをインストールします。

Install Flutter on Linux | Snap Store

直接snap storeからインストールする場合(自動更新)

$ sudo snap install flutter --classic

事前にダウンロードしてインストールする場合

$ snap download flutter
$ sudo snap ack flutter_36.assert #ファイル名はダウンロードしたバージョンで変わります
$ sudo snap install flutter_36.snap --classic #ファイル名はダウンロードしたバージョンで変わります

snapパッケージのインストール後の初回起動時にマニュアルインストール手順でインストールするFlutter SDKを自動的にダウンロードして展開します。これが515MBあるので通信量はあまり削減できません

$ flutter --version
Initializing Flutter
Downloading https://storage.googleapis.com/flutter_infra/releases/stable/linux/flutter_linux_1.22.4-stable.tar.xz
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  1  515M    1 7519k    0     0  1016k      0  0:08:39  0:00:07  0:08:32 1431k
Flutter initialized
Flutter 1.22.4 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 1aafb3a8b9 (4 days ago) • 2020-11-13 09:59:28 -0800
Engine • revision 2c956a31c0
Tools • Dart 2.10.4

  ╔════════════════════════════════════════════════════════════════════════════╗
  ║                 Welcome to Flutter! - https://flutter.dev                  ║
  ║                                                                            ║
  ║ The Flutter tool uses Google Analytics to anonymously report feature usage ║
  ║ statistics and basic crash reports. This data is used to help improve      ║
  ║ Flutter tools over time.                                                   ║
  ║                                                                            ║
  ║ Flutter tool analytics are not sent on the very first run. To disable      ║
  ║ reporting, type 'flutter config --no-analytics'. To display the current    ║
  ║ setting, type 'flutter config'. If you opt out of analytics, an opt-out    ║
  ║ event will be sent, and then no further information will be sent by the    ║
  ║ Flutter tool.                                                              ║
  ║                                                                            ║
  ║ By downloading the Flutter SDK, you agree to the Google Terms of Service.  ║
  ║ Note: The Google Privacy Policy describes how data is handled in this      ║
  ║ service.                                                                   ║
  ║                                                                            ║
  ║ Moreover, Flutter includes the Dart SDK, which may send usage metrics and  ║
  ║ crash reports to Google.                                                   ║
  ║                                                                            ║
  ║ Read about data we send with crash reports:                                ║
  ║ https://flutter.dev/docs/reference/crash-reporting                         ║
  ║                                                                            ║
  ║ See Google's privacy policy:                                               ║
  ║ https://policies.google.com/privacy                                        ║
  ╚════════════════════════════════════════════════════════════════════════════╝

デフォルトではクラッシュ時にGoogleにデータを送る設定になっているので、好みで無効にします。

$ flutter config --no-analytics
Analytics reporting disabled.

You may need to restart any open editors for them to read new settings.

dartはインストールしていない場合はFlutterに同梱のものが使われますが、事前にインストールしているものがある場合は使われるPATHが変わります。

$ which flutter dart
/snap/bin/flutter
/usr/bin/dart

この段階でflutter doctorで何が不足しているか確認します。

$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 1.22.4, on Linux, locale ja_JP.UTF-8)
[!] Android toolchain - develop for Android devices
    ✗ Unable to locate Android SDK.
      Install Android Studio from:
      https://developer.android.com/studio/index.html
      On first launch it will assist you in installing the Android SDK
      components.
      (or visit https://flutter.dev/docs/get-started/install/linux#android-setup
      for detailed instructions).
      If the Android SDK has been installed to a custom location, set
      ANDROID_HOME to that location.
      You may also want to add it to your PATH environment variable.

    ✗ No valid Android SDK platforms found in /usr/lib/android-sdk/platforms.
      Directory was empty.
[!] Android Studio (not installed)
 
[!] Connected device                          
    ! No devices available

! Doctor found issues in 3 categories.

Android SDKはまだ何もしていないので、そもそも見つけられていない状態です。

Android SDKのインストール

Android SDKはサードパーティーのsnapパッケージがあったので、今回はこれを使いました。

Install Android SDK Manager on Linux | Snap Store

直接snap storeからインストールする場合(自動更新)

$ sudo snap install androidsdk

事前にダウンロードしてインストールする場合

$ snap download androidsdk
$ sudo snap ack androidsdk_36.assert #ファイル名はダウンロードしたバージョンで変わります
$ sudo snap install androidsdk_36.snap #ファイル名はダウンロードしたバージョンで変わります

注意点としては、普通にAndroid SDKを環境構築した場合に使うsdkmanagerコマンドがandroidsdkコマンドに置き換わるので、sdkmanagerコマンドを参照しているものを動かす場合に見つからないというエラーが出る可能性が有ります。

flutter doctorで妥協できるところまで持っていく

必要なパッケージをインストールする

必要になりそうなもの、flutter doctorで指摘されそうなものをAndroid SDKでインストールします。2これが一番通信量が多いです。

$ androidsdk 'platforms;android-29' 'system-images;android-30;google_apis_playstore;x86_64' 'add-ons;addon-google_apis-google-24' 'build-tools;28.0.3' 'cmdline-tools;latest' 'extras;m2repository;com;android;support;constraint;constraint-layout-solver;1.0.2' 'extras;m2repository;com;android;support;constraint;constraint-layout;1.0.2' 'sources;android-29'

Android SDKのパスを環境変数ANDROID_SDK_ROOTで指定します。3

$ export ANDROID_SDK_ROOT=~/AndroidSDK

以降、Flutter作業の際にANDROID_SDK_ROOTを設定する必要があるので、ログイン時に設定するように~/.bashrcの末尾に追記します。

--- .bashrc.org	2020-11-18 22:45:50.037307933 +0900
+++ .bashrc	2020-11-18 22:46:32.175392985 +0900
@@ -115,3 +115,6 @@
     . /etc/bash_completion
   fi
 fi
+
+# Android development
+export ANDROID_SDK_ROOT=~/AndroidSDK

インストールしたもののライセンスを片っ端から確認した後、flutter doctorしてみます。

$ flutter doctor --android-licenses #ライセンス確認
$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 1.22.4, on Linux, locale ja_JP.UTF-8)
 
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
[!] Android Studio (not installed)
[!] Connected device
    ! No devices available

! Doctor found issues in 2 categories.

ひとまず今回はここまでにします。この時点の~/AndroidSDKディレクトリ自体をコピーしておくことで、同じamd64アーキテクチャの環境でAndroid SDKを使い回すことができます。

IntelliJ IDEAのインストール

JetBrainsのIDEは公式でsnapパッケージがあるので、今回はIntelliJ IDEAのCommunity Editionをsnapパッケージでインストールします。

Install IntelliJ IDEA Community Edition on Linux | Snap Store

直接snap storeからインストールする場合(自動更新)

$ sudo snap install intellij-idea-community --classic

事前にダウンロードしてインストールする場合

$ snap download intellij-idea-community
$ sudo snap ack intellij-idea-community_257.assert #ファイル名はダウンロードしたバージョンで変わります
$ sudo snap install intellij-idea-community_257.snap --classic #ファイル名はダウンロードしたバージョンで変わります

サンプルプログラムの作成・実行

IntelliJ IDEAのAndroid SDK設定

IntelliJ IDEA起動から右下の「⚙Configure」→「Settings」を選択して設定画面に入ります。

左上のフィルタにandroidを入力すると候補が出るので、「Appearance & Behavior」→「System Settings」→「Android SDK」を選択し、「Android SDK Location」の右にあるEditをクリックします。

Android SDKの画面になりますが、このまま進むとAndroid SDKをダウンロードする羽目になるので、Android SDK Locationが~/AndroidSDKではないことを確認4して右にあるディレクトリ選択ボタンをクリックします。

ディレクトリ選択では一旦ホームディレクトリを選択して閉じるなどした後に再度選択画面を開くと~/AndroidSDKを選べるようになるので、選択するとダウンロード済みのパッケージが表示され、ダウンロードサイズが0に変わったことがわかります。Nextで先に進み、確認画面をやり過ごします。

設定画面に戻ってくると指定したディレクトリが反映されていることがわかります。OKで設定画面を閉じます。

IntelliJ IDEAのFlutter(・Dart)プラグイン設定

IntelliJ IDEA起動から右下の「⚙Configure」→「Plugins」を選択して設定画面に入ります。

表示されたプラグインウィンドウでFlutterを選択し、Installボタンをクリックします。左側に表示されている人気プラグインの中にあるのですぐ見つかると思います。

途中、Dartのプラグインもインストールするよう表示されるので、そのままインストールして完了したらIDEAを再起動します。

プロジェクトの作成(・Flutter SDKの設定)

IntelliJ IDEAを起動したら、「New Project」をクリックします。

作成するプロジェクトの種類を選ぶ画面でFlutterを選択すると、右側に空欄のFlutter SDK pathがあるので、…をクリックして~/snap/flutter/common/flutterを設定します。

Flutter SDK pathが設定されたらNextをクリックします。

Project nameのみmyappという名前に変更しています。Android languageは最終的にコードはDartになるのでどちらを選んでも違いはないと思います。

Finishをクリックするとサンプルソースの一式が配置されたプロジェクトが作られます。メニューから「File」→「Project Structure…」を選択します。

「Project Settings」→「Project」を選び、Project SDKにAndroid SDKでダウンロードしているパッケージを選択します。

Android API 30 Platformを選んでいますが、手順に沿ってインストールした場合は29が選べると思います。問題ありません。

これでビルドの準備までは終わったので、実行時に使うAndroidデバイスの作成に移ります。

Androidデバイスの作成

IntelliJ IDEAからAndroidで使うプログラムを実行する際の環境である仮想Androidデバイスを作成します。実Android端末があってそれを使う場合はこの作業は不要です。

avdmanagerコマンドがJAXB使ってるけどJava11以降はJAXB標準で入ってないんだよね…→Java8を使用

唐突にJavaの話になりますが、JavaでXMLを扱う時にJavaのクラスをXMLにする/XMLをJavaのクラスにするマッピングをするJAXB(Java Architecture for XML Binding)という規格があります。

このJAXBはJava6でJDKに同梱されるようになったので、Java6以降のJavaは(意図して外さない限りは)JAXBが使えるはずでした。仮想Androidデバイスを作成するためにavdmanagerコマンドを実行した結果が以下の通り。

$ ~/AndroidSDK/tools/bin/avdmanager list
Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema
	at com.android.repository.api.SchemaModule$SchemaModuleVersion.<init>(SchemaModule.java:156)
	at com.android.repository.api.SchemaModule.<init>(SchemaModule.java:75)
	at com.android.sdklib.repository.AndroidSdkHandler.<clinit>(AndroidSdkHandler.java:81)
	at com.android.sdklib.tool.AvdManagerCli.run(AvdManagerCli.java:213)
	at com.android.sdklib.tool.AvdManagerCli.main(AvdManagerCli.java:200)
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.XmlSchema
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
	... 5 more

NoClassDefFoundErrorはJavaプログラムが(あるはずの)classファイルを呼び出した時に該当するclassファイルが見つからない場合に発生するエラーで、javax/xml/bindということはjava.xml.bindパッケージが見つからないことを指していて、これはJAXBのパッケージがないJavaの状態を表しています。

先程JAXBはJava6でJDKに同梱されるようになったと書きましたが、その後Java11でJAXBはJavaの標準APIから外れた為、以下に示す現時点でサポート中のJavaのバージョンを考えると選択肢は実質Java8を使うこと一択となります。5

  • Java8→JAXB同梱
  • Java11→JAXBなし
  • Java15(現時点での最新バージョン)→JAXBなし

update-alternativesコマンドでjavaコマンド実行時に呼び出されるJavaのバージョンをJava8にします。

# update-alternatives --config java
alternative java (/usr/bin/java を提供) には 3 個の選択肢があります。

  選択肢    パス                                          優先度  状態
------------------------------------------------------------
  0            /usr/lib/jvm/java-15-openjdk-amd64/bin/java      1511      自動モード
* 1            /usr/lib/jvm/java-11-openjdk-amd64/bin/java      1111      手動モード
  2            /usr/lib/jvm/java-15-openjdk-amd64/bin/java      1511      手動モード
  3            /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java   1081      手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください: 3
update-alternatives: /usr/bin/java (java) を提供するためにマニュアルモードで /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java を使います

改めてavdmanagerコマンドを実行します。

$ ~/AndroidSDK/tools/bin/avdmanager list target
(snip)
----------
id: 1 or "android-29"
     Name: Android API 29
     Type: Platform
     API level: 29
     Revision: 5
----------
id: 2 or "android-30"
     Name: Android API 30
     Type: Platform
     API level: 30
     Revision: 3

無事に実行できるようになりました。普段Javaを使う場合は(次のLTSであるJava17がリリースされるまでは)Java11を使うことが多くなると思いますので、個人的にはAndroidデバイスを作り終わったら再度update-alternativesコマンドでJava11に戻した方が良いと思います。

avdmanagerコマンドで仮想Androidデバイスを作成

今回はSDK30のPlay Storeが利用可能なシステムイメージでデバイスを作成します。引数ーnの後ろに名前を指定します。今回は名前を「flutteravd」にしています。

$ ~/AndroidSDK/tools/bin/avdmanager create avd -n flutteravd -k 'system-images;android-30;google_apis_playstore;x86_64'
$ ~/AndroidSDK/tools/bin/avdmanager list avd
Available Android Virtual Devices:
    Name: flutteravd
    Path: /home/hogehoge/.android/avd/flutteravd.avd
  Target: Google Play (Google Inc.)
          Based on: Android API 30 Tag/ABI: google_apis_playstore/x86_64

AndroidデバイスでFlutterアプリを実行

Androidデバイスがある状態でIntelliJ IDEAを起動すると、上部のVCSメニューの下あたりにある<no devices>を下から選べるようになります。選ぶと仮想Androidデバイスの場合はAndroid端末が立ち上がります。

Androidデバイスが接続されている状態で main.dartの右の再生ボタンをクリックすると仮想AndroidデバイスでFlutterアプリが実行されます。

お疲れ様でした。

スポンサーリンク


  1. 特にAndroid SDKで顕著 [return]
  2. 実際には最初に’platforms;android-30’と’build-tools;30.0.2’をインストールしましたが、IntelliJ IDEAのFlutterプラグインが’platforms;android-29’と’build-tools;28.0.3’を自動的にインストールしたため、インストールするパッケージを変えています。flutter doctorの結果などではパッケージのバージョンが異なったりするのはこのためです。 [return]
  3. ANDROID_HOMEは古いらしい [return]
  4. なぜか指定されているディレクトリが~/Android/Sdkという微妙に惜しい名前になっていますが [return]
  5. javaコマンドの引数を指定できるような使い方であれば参照するjarとしてJAXBを追加すれば回避できますが、普通のコマンドとして呼んでいる中で発生しているので非常に面倒です [return]

comments powered by Disqus