- 投稿日:2019-08-30T23:03:37+09:00
Flutter 1.7.x 環境をmacOS上に構築する
なぜこの文章を書いているか?
この文章(Flutter 1.2.x 環境をmacOS上に構築する)を過去に書き間が空いたのと再度Flutterを触り始めたので環境をまっさらな状態から作り直した作業ログとしてまとめたのが以下です。最近はLaravelとかNuxt.jsとかTypeScriptとかいじってますが、そろそろ他のものもということで。
今回はできる限り公式サイトの順番で環境を作っていこうと思います。
https://flutter.dev/docs/get-started/install/macos環境(2019/08/30(金)現在)
- macOS Mojave(10.14.6)
- Xcode 10.3
- IntelliJ IDEA Ultimate 2019.2.1
- Flutter 1.7.8 + Hotfix 4 Stable
インストール
Tools
公式サイトに書かれている必須ツールは以下の通り。
- bash
- curl
- git 2.x
- mkdir
- rm
- unzip
- which
このうち、macOS Mojaveに標準で入っていないのは
git
なのでインストールする。command$ xcode-select --install「"xcode-select"コマンドを実行するには、コマンドライン・デベロッパ・ツールが必要です。ツールを今すぐインストールしますか?」とウィンドウが表示されたら
インストール
をクリック。
「Command Line Tools使用許諾契約」画面が表示されたら内容を読んだ上で同意する
をクリック。インストールが完了したら以下でバージョンが表示されればOK。
command$ git --version git version 2.20.1 (Apple Git-117)Flutter SDKのインストール
公式サイトの
flutter_macos_v1.7.8+hotfix.4-stable.zip
と書かれている青いボタンをクリックしてZipファイルをダウンロードします。
ダウンロードしたら、~/development
以下に展開します。command$ mkdir ~/development $ cd ~/development $ unzip ~/Downloads/flutter_macos_v1.7.8+hotfix.4-stable.zip
~/development/flutter/bin/
が作られるのでPATHを通します。command$ echo 'export PATH=$PATH:~/development/flutter/bin' >> ~/.profile $ exec $SHELL -l以下でバージョン情報が表示されればOK。
command$ flutter --version Flutter 1.7.8+hotfix.4 • channel stable • https://github.com/flutter/flutter.git Framework • revision 20e59316b8 (6 weeks ago) • 2019-07-18 20:04:33 -0700 Engine • revision fee001c93f Tools • Dart 2.4.0以下でバイナリをダウンロード(キャッシュ)しておきます。瞬間で終わるので実際に何か行われている感じはしないのですが、念の為。
command$ flutter precache
Flutterの実行に必要な環境が揃っているか以下でチェックします。
途中「"gen_snapshot"はこのMac用に最適化されていないため、アップデートが必要です。」と出ますのでOK
をクリックします。command$ flutter doctor -v [✓] Flutter (Channel stable, v1.7.8+hotfix.4, on Mac OS X 10.14.6 18G95, locale ja-JP) • Flutter version 1.7.8+hotfix.4 at /Users/foobar/development/flutter • Framework revision 20e59316b8 (6 weeks ago), 2019-07-18 20:04:33 -0700 • Engine revision fee001c93f • Dart version 2.4.0 [✗] 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/setup/#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. [✗] Xcode - develop for iOS and macOS ✗ Xcode installation is incomplete; a full installation is necessary for iOS development. Download at: https://developer.apple.com/xcode/download/ Or install Xcode via the App Store. Once installed, run: sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer ✗ CocoaPods not installed. CocoaPods is used to retrieve the iOS and macOS platform side's plugin code that responds to your plugin usage on the Dart side. Without CocoaPods, plugins will not work on iOS or macOS. For more info, see https://flutter.dev/platform-plugins To install: brew install cocoapods pod setup ! Brew can be used to install CocoaPods. Download brew at https://brew.sh/. [✗] iOS tools - develop for iOS devices ✗ libimobiledevice and ideviceinstaller are not installed. To install with Brew, run: brew update brew install --HEAD usbmuxd brew link usbmuxd brew install --HEAD libimobiledevice brew install ideviceinstaller ✗ ios-deploy not installed. To install: brew install ios-deploy ! Brew can be used to install tools for iOS device development. Download brew at https://brew.sh/. [!] Android Studio (not installed) • Android Studio not found; download from https://developer.android.com/studio/index.html (or visit https://flutter.dev/setup/#android-setup for detailed instructions). [!] Connected device ! No devices available ! Doctor found issues in 5 categories.色々と未インストール(環境未整備)だと怒られているので順に入れていきます。
Xcodeをインストール
App Store
を起動し、検索窓にxcode
と入力して検索しインストールします。時間がかかるので私は一晩寝かしました。すでにコマンドラインツールはインストール済みですが、公式ドキュメントのとおりにインストールしたXcodeから設定しておきます。
command$ sudo xcode-select --switch /Applications/Xcode.app/Contents/DeveloperXcodeのライセンス承諾を行うために以下のコマンドを実行します。Enterを押した後、Spaceキーで最後まで読み、入力を求められたら
agree
とキー入力してEnterを押してライセンス条項に対し承諾をします。command$ sudo xcodebuild -licenseこの状態で以下のコマンドが実行できgitのバージョンが表示されればOKです。
command$ git --version git version 2.20.1 (Apple Git-117)iOSシミュレータの設定
以下のコマンドを実行しiOSシミュレータを起動します。
command$ open -a Simulator
Hardware
>Device
>Manage Devices
を選択し、「Install additional required components?」画面が出たらInstall
をクリックし、パスワードの入力画面が出るのでMacのアカウントのパスワードを入力しOK
をクリックします。インストールが起動したらXcodeが起動するので、一旦iOSシミュレータを終了して再度起動します。私の環境ではiPhone XRのシミュレータが自動的にスタートしました。公式ドキュメントには「64bitのiPhone5S以降をセットアップしてね」とありますが現在のiOSシミュレータではこれ以上特に作業は必要ありません。
テストアプリを作ってみる
公式ドキュメントではここで唐突にテストアプリを作る項目が出てきます。iOSシミュレータがセットアップできているかなどのチェック用でしょうか?ここでは言われたとおりに作ってみることにします。
ターミナルで適当な場所に作業用ディレクトリを作成し、そこで作業を進めます。
command$ mkdir ~/development/project $ cd ~/development/project $ flutter create my_app $ cd my_app $ flutter run No connected devices. Run 'flutter emulators' to list and start any available device emulators. If you expected your device to be detected, please run "flutter doctor" to diagnose potential issues, or visit https://flutter.dev/setup/ for troubleshooting tips.怒られました。どうやらiOSシミュレータを終了していたためのようです。iOSシミュレータを起動しiPhone XRのシミュレータが起動している状態でもう一度
flutter run
を実行してみます。
Flutter Demo Home Page
という画面がシミュレータに表示されればOKです。ターミナルでq
を入力するとアプリが終了します。iOSデバイス(実機)にデプロイするための設定
Homebrewをインストールするように書かれているのでそのとおりにします。Qiitaを読んでらっしゃるMacユーザならインストール済みと思われますので(偏見)説明は省きます。
command$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" $ brew updateiOSデバイス(実機)にデプロイするために必要なツール群を
brew
コマンドを使ってインストールしていきます。私の環境ではbrew link usbmuxd
で「リンク済み」の旨のメッセージが出ましたが特に問題ないと思われます。command$ brew install --HEAD usbmuxd $ brew link usbmuxd $ brew install --HEAD libimobiledevice $ brew install ideviceinstaller ios-deploy cocoapods $ pod setup先ほど作ったテストアプリをiOSデバイスにデプロイできるようにするためにプロジェクトにサインをします。基本公式ページのとおりですが簡単にまとめます。
- ターミナルで
open ios/Runner.xcworkspace
としてXcodeを開きます- iOSデバイスをMacに接続して「信頼するか?」など聞かれたら通常の方法でMacとiOSデバイスが通信できる状態にします
- Xcodeの左上のプルダウンが
Runner > iPhone XR
となっていたら、プルダウンをクリックして接続したiOSデバイスを選択します- 左ペインの一番上にある
Runnerプロジェクト
をクリックして選択します- Xcode 9と10は真ん中のペインの
General > Signing > Team
を、Xcode 11はSigning & Capabilities > Team
にあるTeam
メニューに自分のチーム(Apple ID)を設定します- 自分の環境では「You currently don't have access to this membership resource. To resolve this issue, agree to the latest Program License Agreement in your developer account.」と出ていたのでDev Centerにアクセス、その後
account
にメニューから移動し「The Apple Developer Program License Agreement has been updated.」と赤背景でメッセージが出ているところから「Review Agreement」をクリック、内容を確認しチェックボックスをチェック、「I Agree」ボタンをクリック、最後にXcodeに戻ってエラーメッセージの下の「Try again」ボタンをクリックしました- iOSシミュレータを終了した上でターミナルから
flutter run
を実行- 先ほどと同じ
Flutter Demo Home Page
がiOSデバイスで表示されたらOKですAndroid Studioの代わりにIntelliJ IDEA Ultimateをインストールする
公式サイトではAndroid Studioをインストールしていますが、私はIntelliJ IDEAを普段使っているのでそちらで利用可能なように設定します。
まず、
Homebrew Cask
を使ってJetBrains ToolBox
をインストールします。command$ brew cask install jetbrains-toolboxApplicationから
JetBrains ToolBox
を起動し、JetBrainsアカウント
でログイン後、IntelliJ IDEA Ultimateをインストールします。
インストールが終わったらIntelliJ IDEAを起動します。初期設定の時にAndroid開発の追加インストールがされているはずですので、Welcome画面からCreate New Project
を選択し、New Project
画面でAndroid
を選択するとConfigure Android SDK
画面が表示されるのでInstall SDK
ボタンをクリックします。
Next
をクリックしていき最後にFinish
をクリックすると${USER_HOME}/Library/Android/sdk/
以下にAndroid SDK
がインストールされます。Choose your project
画面に戻ったら今回はcancel
をクリックしてキャンセルします。Androidデバイスの設定
公式ページを見ながら順に設定していきます。
- Androidデバイスの
開発者オプション
とUSBデバッグ
を有効にします。デバイスやOSのバージョンによりますが通常はビルド番号を何回かタップすると開発者オプション
が有効になり、設定 > システム > 開発者オプション
からUDBデバッグ
のオン・オフができます- USBケーブルでMacとAndroidデバイスを接続します。
- ターミナルで
fultter devices
を実行して接続したデバイスが1 connected device:
などと表示されればOKです。表示されない場合やDevice XXXXXXXX is not authorized.
と出ている場合は再接続やデバイスの認証、USB設定などを見直してみてくださいこの状態でターミナルからIntelliJ IDEAを起動し、Androidデバイスにデプロイしてみます。以下でターミナルから開けない場合は手動で
~/development/project/my_app/android
をIntelliJ IDEAで開きます。command$ cd ~/development/project/my_app $ idea ./android最初はプロジェクトのインデックスに時間がかかります。インデックスが終わると私の環境では2つwarningが出ました。
- Warning: License for package Android SDK Build-Tools 28.0.3 not accepted.
- Warning: License for package Android SDK Platform 28 not accepted.
ライセンスについて承諾していないのが理由のようです。色々と調べると
Android SDK
のsdkmanager
で承諾することができそうです。とりあえず実行してみます。command$ ~/Library/Android/sdk/tools/bin/sdkmanager --licenses No Java runtime present, requesting install.おっとJava runtimeのインストールがまだでした。宗教上の理由でanyenvを使います。
command$ brew install anyenv $ anyenv install --init $ echo 'eval "$(anyenv init --no-rehash -)"' >> ~/.profile $ exec $SHELL -l $ anyenv install jenv $ exec $SHELL -l $ brew tap caskroom/versions $ brew cask install adoptopenjdk8 $ jenv add $(/usr/libexec/java_home -v 1.8) $ jenv global 1.8 $ java -version openjdk version "1.8.0_222" OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_222-b10) OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.222-b10, mixed mode)もう一度
sdkmanager
を起動します。command$ ~/Library/Android/sdk/tools/bin/sdkmanager --licenses色々とライセンスの承諾を聞かれるので
y
を入力していきます。
最後にAll SDK package licenses accepted
と出ればOKです。
Build
タブからBuild
を再実行してみるとandroid:successful
となりWarningは消えました。
Run > Edit configurations...
を選択し、左上の+
をクリックしてAndroid App
を選択します。Name
をmy_app
に変更、Module
にapp
を選択しApply
、OK
をクリックして画面を閉じます。
Run > Run 'my_app'
を選択すると、どのデバイスをビルドターゲットにするか聞かれるのでUSBで接続したAndroidデバイスを選択しOK
をクリックするとビルドが始まり、自動的にデバイスにデプロイされ、テストアプリが起動します。Androidエミュレータの設定
IntelliJ IDEAからAndroidエミュレータが動作するように設定します。
Tools > Android > AVD Manager
を選択+ Create Virtual Device...
をクリックPhone > Nexus 5X
を選択しNext
をクリックPie
の隣のDownload
をクリックしPie
をインストールしますPie
のインストールが終了したらFinish
をクリック- 改めて
Pie
を選択しNext
をクリックFinish
をクリックADV Manager
を一旦閉じ、Run > Run 'my_app'
を選択Select deployment target
画面にNexus 5X
があるので選択してOK
をクリック- エミュレータが自動で起動します
- エミュレータが起動すると自動的にデプロイされ、テストアプリが起動します
落ち穂拾い
fultter doctor -v
を実行して問題を確認します。command$ flutter doctor -v (中略) [!] Android toolchain - develop for Android devices (Android SDK version 29.0.2) • Android SDK at /Users/foobar/Library/Android/sdk • Android NDK location not configured (optional; useful for native profiling support) • Platform android-29, build-tools 29.0.2 • Java binary at: /Library/Java/JavaVirtualMachines/adoptopenjdk-12.0.2.jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment AdoptOpenJDK (build 12.0.2+10) ✗ Android license status unknown. Try re-installing or updating your Android SDK Manager. See https://developer.android.com/studio/#downloads or visit https://flutter.dev/setup/#android-setup for detailed instructions. (中略) [!] Android Studio (not installed) • Android Studio not found; download from https://developer.android.com/studio/index.html (or visit https://flutter.dev/setup/#android-setup for detailed instructions). [!] IntelliJ IDEA Ultimate Edition (version 2019.2.1) • IntelliJ at /Users/foobar/Applications/JetBrains Toolbox/IntelliJ IDEA Ultimate.app ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. • For information about installing plugins, see https://flutter.dev/intellij-setup/#installing-the-plugins (中略) ! Doctor found issues in 3 categories.
Android SDK
のライセンスが不明ということなので、flutter doctor --android-license
を実行してみます。command$ flutter doctor --android-licenses All SDK package licenses accepted.
Android Studio
はわざといれていないのでここでは無視します。
IntelliJ IDEA
にFlutter
とDart
のプラグインが入っていないと言われているのでインストールしてIntelliJ IDEAをリスタートします。もう一度
flutter doctor -v
を実行します。command$ flutter doctor -v (中略) [!] Android Studio (not installed) • Android Studio not found; download from https://developer.android.com/studio/index.html (or visit https://flutter.dev/setup/#android-setup for detailed instructions). (中略) ! Doctor found issues in 1 category.
Android Studio
以外のエラーが消えました。これで開発環境が揃ったことになります。まとめ
前回のインストールログをまとめてから、ちょっとしたサンプルプログラムを作っただけだったので、今度はもうちょっとちゃんとしたものを作りたいなぁと考えています(^^;
- 投稿日:2019-08-30T21:35:15+09:00
keystoreファイルのfingerprintの調べ方
コマンド
keystore
ファイルがある場所へ移動し、下記を打ち込む。
keytool -list -keystore [file name]
$ keytool -list -keystore my-upload-key.keystore Enter keystore password: Keystore type: jks Keystore provider: SUN Your keystore contains 1 entry my-key-alias, Aug 28, 2019, PrivateKeyEntry, Certificate fingerprint (SHA1): F5:A5:7E:6F:C2:CE:08 Warning: The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore my-upload-key.keystore -destkeystore my-upload-key.keystore -deststoretype pkcs12".
- 投稿日:2019-08-30T21:12:14+09:00
AsyncTaskLoaderは衰退したのか?
〇概要
久々にAsyncTaskLoaderを使ったらsupportLoaderManagerが非推奨になっていました。
'getter for supportLoaderManager: LoaderManager!' is deprecated. Deprecated in JavaloaderManagerも同じく
'getter for loaderManager: LoaderManager!' is deprecated. Deprecated in Java〇調査
とりあえず公式
https://developer.android.com/reference/android/content/AsyncTaskLoaderAPI level 28から非推奨と
たしかに
implementation 'com.android.support:appcompat-v7:28.0.0'
のバージョンを下げると警告は消えました。Revisionsを見てみると
Revision 28.0.0 Productionは[September 21, 2018]からリリースなので1年ぐらい前ですね。
Revision 27.1.0 Release
には以下のようなことが
The underlying implementation of Loaders has been rewritten to use Lifecycle. While the API remains unchanged, there are a number of behavior changes:
ローダー関係はアーキテクチャーライブラリを使うように書き換えるよと。stackoverflowの投稿を読んでみると、アクティビティやフラグメントのライフサイクルの流れを考えると、ViewModelやLiveData等のアーキテクチャコンポーネントを使うほうが適切になったそうです。
もう利用頻度は大分減った技術なんですかね・・・
しかし、警告にあるようにSupport Libraryではまだ使えるます!
https://developer.android.com/reference/android/support/v4/content/AsyncTaskLoader.htmlしたがって修正
〇対応
XXX.ktgetSupportLoaderManager().initLoader(LOADER_TAG_METADATA,bundle,callback) ↓ LoaderManager.getInstance(this).initLoader(LOADER_TAG_METADATA,bundle,callback) loaderManager.destroyLoader(loader.id) ↓ LoaderManager.getInstance(this@MainActivity).destroyLoader(loader.id)〇結果
これで警告は解除。
しかし、やはり時代はAndroidのアーキテクチャーコンポーネントを自在に使いこなせるようにならないとダメみたいですね。
- 投稿日:2019-08-30T20:05:33+09:00
Bitriseのナンバリングを利用して、バージョンの自動インクリメントを実現(ReactNative, android)
下記記事でFastlaneをBitriseに組み込み、google play consoleへの自動デプロイを実現しました。
FastlaneのコマンドをBitriseに組み込む(android,ReactNative)
しかし、開発の現場ですとデプロイ毎にバージョン番号を繰り上げて管理したいです。
そこで利用するのが、Bitriseのナンバリング番号です。ios版はこちら↓
Bitriseのナンバリングを利用して、バージョンの自動インクリメントを実現(ReactNative, ios)Bitriseのナンバリング番号とは
Build numbering and app versioning
Bitriseのworkflowが動く際に管理されている番号のことです。
実行毎に番号が繰り上がるため、この番号をバージョン番号として使用しようと思います。設定
android/app/build.gradle
のversionCode
を下記のように変更します。
Bitriseのデフォルトの環境変数であるBITRISE_BUILD_NUMBER
を使用します。android/app/build.gradledefaultConfig { applicationId "com.reactnativeplatformBitrise" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion Integer buildNumb = System.getenv("BITRISE_BUILD_NUMBER") as Integer versionCode buildNumb ?: 1 versionName "1.0" ndk { abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64' } }これに伴い下記記事で作成したファイルの
increment
の機能は不要になるため、該当部分を削除します。
fastfileの編集android/fastlane/Fastfiledesc "submit internal release to Google Play Store" lane :internal do # 下記のincrement機能は削除 # increment_version_code( # gradle_file_path: "./app/build.gradle" # ) # make apk file gradle(task: "assembleRelease") # find the apk file supply( track: "internal", apk: "#{lane_context[SharedValues:: GRADLE_APK_OUTPUT_PATH]}" )実行
上記設定でBitriseが動きますと、google play consoleにてバージョン番号がBitriseのナンバリング番号と一致しているのが確認できます。
参考
- 投稿日:2019-08-30T18:58:13+09:00
あなたのToolbarはカスタム or 標準
発信したいこと
久々の投稿でございます.
この記事を書くに至ったのは複数のAndroidプロジェクトを見ていて
Toolbarの実装方法が異なりどちらが実装しやすいのかなと思い投稿させていただきました。
やり方は様々あるのであくまで一つのやり方として参考にしてもらえれば幸いです!環境
Mac : 10.14.3
AndroidStudio : 3.4.2
Language : Kotlin実装
カスタムのxml
Toolbarの中にゴリゴリ、レイアウトを実装しています.
<android.support.v7.widget.Toolbar android:id="@+id/toolbar1" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@color/colorPrimary"> <android.support.constraint.ConstraintLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/navigationImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_arrow_back_24dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" tools:ignore="ContentDescription"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/title" android:layout_marginStart="28dp" android:textSize="20sp" android:textColor="@color/white" app:layout_constraintTop_toTopOf="@+id/navigationImageView" app:layout_constraintBottom_toBottomOf="@+id/navigationImageView" app:layout_constraintStart_toEndOf="@+id/navigationImageView"/> <ImageView android:id="@+id/menuImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_settings_24dp" android:layout_marginEnd="20dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="parent" tools:ignore="ContentDescription"/> </android.support.constraint.ConstraintLayout> </android.support.v7.widget.Toolbar>標準のxml
スッキリして見やすいですね!
<android.support.v7.widget.Toolbar android:id="@+id/toolbar2" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@color/colorPrimaryDark" app:title="@string/title" app:titleTextColor="@color/white" app:navigationIcon="@drawable/ic_arrow_back_24dp"/>所感
カスタム
- メリット
自由自在にレイアウトできる。 iOSと同じようにして欲しい要望に答えることができる- デメリット
複数エンジニアが開発している場合、全画面のToolbarを同様にすることが難しい標準
- メリット
コードを初見で理解できる- デメリット
特に見当たらないコード見たい人はココ
https://github.com/m-saeki0926/toolbar_sample_android
参考
https://developer.android.com/reference/android/support/v7/widget/Toolbar
- 投稿日:2019-08-30T18:50:40+09:00
Google play consoleへデプロイする際のエラー[not compliant with the Google Play 64-bit ](ReactNative)
エラー
Google play consoleへアプリをデプロイ(
.apk
ファイルのアップロード)の際に、下記のようなエラーが発生しました。This release is not compliant with the Google Play 64-bit requirement解決法
android/app/build.gradle
のndk部分を下記書き換えた上で.apk
ファイルの発行->再度、google play consoleへアップロードdefaultConfig { applicationId "jp.co.hogehoge" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" ndk { abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64' } }参考
- 投稿日:2019-08-30T18:40:01+09:00
Google play consoleへアプリをデプロイする際のエラー[must target at least api level 28](ReactNative)
- 投稿日:2019-08-30T18:40:01+09:00
Google play consoleへデプロイする際のエラー[must target at least api level 28](ReactNative)
- 投稿日:2019-08-30T18:03:00+09:00
#7 Kotlin で TODO アプリを開発・リリースするまでの記録
前回のあらすじ
前回までの記事
#1 Kotlin で TODO アプリを開発・リリースするまでの記録
#2 Kotlin で TODO アプリを開発・リリースするまでの記録
#3 Kotlin で TODO アプリを開発・リリースするまでの記録
#4 Kotlin で TODO アプリを開発・リリースするまでの記録
#5 Kotlin で TODO アプリを開発・リリースするまでの記録
#6 Kotlin で TODO アプリを開発・リリースするまでの記録前回のあらすじ
- リストに区切り線ができた
- タイトルを設定した
今回の目標
- RecyclerView でデータの追加・削除
RecyclerView でデータの追加・削除
#2 を見返して、RecyclerView を調べた際の参考記事をまねします。
まねする記事はこちらにしました。理由は次の通りです。
- 表示されているリストに追加、削除ができること
- 一時的なデータ保存なので、model などの要素をいったん除外して、目的に絞って作成できそう
それでは早速進めていきます。
Android Support Design Library
design ライブラリをインポートします。
最新のバージョンをインポートするため、#4 の手順に倣って行います。
#4 Kotlin で TODO アプリを開発・リリースするまでの記録
design でライブラリ検索します。
選択肢に AndroidX がないようですが、こういうものなのでしょうか?
「OK」をクリックして反映させます。build.gradle(app)dependencies { implementation 'com.android.support:design:28.0.0' }Version 28 (intended for Android Pie and below) is the last version of the legacy support library, so we recommend that you migrate to AndroidX libraries when using Android Q and moving forward. The IDE can help with this: Refactor > Migrate to AndroidX... less... (Ctrl+F1) Inspection info:There are some combinations of libraries, or tools and libraries, that are incompatible, or can lead to bugs. One such incompatibility is compiling with a version of the Android support libraries that is not the latest version (or in particular, a version lower than your targetSdkVersion). "Issue id: GradleCompatible言われた通りにやっただけなのにエラーが発生。
Refactor > Migrate to AndroidX
AndroidX に変換してください、みたいなことを指示されている気がします。
いや、AndroidX が選択肢にあれば選択してましたけど・・・それに Migrate to AndroidX は、個別に変換するのではなく全体変換するはずです。
変にほかのソースで手直しが発生したら嫌なので試したくないなぁ、と思って、他の方法を調べてみます。小さな Android アプリを AndroidX に置き換えてみる
大体はcom.android.support
->androidx
でいけそうです。ほんとだ・・・
build.gradle(app)dependencies { implementation 'androidx.design:28.0.0' }書き直したらエラーがなくなりました!
それなら最初から AndroidX を選択肢に入れておいてくれ。ビルド実行
本当はもう少し後に気づきましたが、紛らわしいのでここに書いておきます。
ビルドを実行しようとしたら、エラーになりました。
ERROR: Failed to resolve: androidx.design:28.0.0: Affected Modules: appandroidx.design:28.0.0 が解決できないと言われてる・・・
build.gradle(app)dependencies { implementation 'com.android.support:design:28.0.0' }当初設定したライブラリに切り戻してビルドしたところ、無事実行できました。
エラーは相変わらず出ていますが、ビルドが実行できるので問題なしとします。なんでなんや
Material Icons からボタン素材を追加する
Material Icons とは
【Google提供】マテリアルアイコンの使い方とカスタマイズ方法まとめ
Material Icons(マテリアルアイコン)とは、Googleが2014年に提唱したMaterial Design(マテリアルデザイン)です。
ざっくり言うと、どのデバイスでもデザインを統一させて、使いやすくしていきましょうという動きですね。数多あるフリーアイコンの中で、Material Icons を選ぶのはほかでもなく、Android Studio から直接挿入できる利便性です。
後は Google 先生の出したデザインなので間違いないです。すりすり。+ - ボタン素材を追加する
アプリ内ボタンにマテリアルデザインアイコンを使う [Android]
さくっとボタン素材となるアイコンイメージを追加しました。
- ic_add_black_24dp.xml
- ic_remove_black_24dp.xml
Item のレイアウトを作成
1 行に対するレイアウトは、これまでの作業の中で list_item.xml として作成しています。
基本仕様ではテキスト欄が 1 つだけなので、TextView は 1 つで良さそうです。ビルド実行
いいかんじ!
list_item.xml
変更したソースコードはこちらです。
list_item.xml<androidx.cardview.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" card_view:cardElevation="2dp" android:foreground="?android:attr/selectableItemBackground"> <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:orientation="horizontal" android:paddingStart="25dp" android:paddingEnd="0dp" android:gravity="center_vertical"> <TextView android:id="@+id/itemTextView" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1"/> <ImageButton android:id="@+id/itemImageButton" android:layout_width="70dp" android:layout_height="match_parent" android:background="#000f" card_view:srcCompat="@drawable/ic_remove_black_24dp" android:contentDescription="@string/app_name"/> </LinearLayout> </androidx.cardview.widget.CardView>ImageView がなくなり、ImageButton が入った以外にも、レイアウトを整えるためいろいろ変更しました。
ワーニングが発生したため、追加したプロパティもあります。LinearLayout
android:paddingStart="25dp"
左端からテキスト開始位置をずらすために追加しました。
CSS では padding-left です。
android:paddingEnd="0dp"
レイアウト的には paddingStart のみで問題なかったのですが、paddingStart を入れるなら paddingEnd も入れるようにとのワーニングが発生したため追加しました。
値を正数にするとボタン位置が右端からずれてしまうので、0 指定です。
CSS では padding-right です。TextView
android:layout_width="0dp"
当初は
0 dp
ではなくwrap_content
を指定していましたが、次のワーニングが出たので変更しました。Use a layout_width of 0dp instead of wrap_content for better performance横幅を指定しないことになりますが、次項の
layout_width
が横幅を担います。
android:layout_weight="1"
View に対してアイテムの表示範囲を比率で指定できます。
CSS では flex-grow のようなものだと思っています。View に対してアイテムが横並びになっているとします。
以下のように割り当てられるイメージです。100 dp の View の場合 [layout_weight="2"] → 20dp [layout_weight="8"] → 80dp 200 dp の View の場合 [layout_weight="2"] → 40dp [layout_weight="8"] → 160dp
layout_weight="1"
を指定し、もうひとつの値を固定値にすれば、一方のみレスポンシブ対応が可能です。100 dp の View の場合 [layout_width="20dp"] → 20dp [layout_weight="1"] → 80dp 200 dp の View の場合 [layout_width="40dp"] → 40dp [layout_weight="1"] → 160dp今回はボタンのサイズを変えずに、テキストの長さがレスポンシブになるデザインが望ましいと考えたので、
layout_weight="1"
にしました。レスポンシブデザインの考え方としては以下の通りです。
【図解】レスポンシブデザインとは?定義、特徴、メリットとデメリットを解説
マルチスクリーンではないので必要なのかわかりませんが、意識して適用したのでここに記載しておきます(アプリより WEB 的な考え方だと思います)。
この考え方でなくとも、長さを可変にしたい場合に最適です。ImageButton
android:layout_width="70dp"
前述の通りです。
現在の View サイズから鑑みて、固定値を割り当てました。
android:layout_height="match_parent"
リストの縦幅に対して最大値にしています。
理由は誤タップを防ぐためです。
android:contentDescription="@string/app_name"
Image には Description を指定するようにとワーニングが出たので追加しました。
最初は文字列にしようとしましたが、@string
を挿入するようにとのワーニングが出て、@string
と入力すると補完候補が表示されたため、流されるまま@string/app_name
を指定しました。Android Studio が全部導いてくれます。
そして次第にワーニングに踊らされている気分になっていく。余談:paddingStart と paddingLeft
- paddingStart と paddingEnd
- paddingLeft と paddingRight
これらは基本的に同じ動作のようです。
前者は左からの余白、後者は右からの余白を指定します。
違いとしては次の記事をお読みください。文字が左から開始する言語、右から開始する言語に対応できるように、左右ではなく文字の開始位置という概念で使用とするようです。
そもそもソース上で Left を書いても、Start を使用するようにとワーニングが発生するので、大人しく従いましょう。Consider adding android:paddingStart=“25dp” to better support right-to-left layouts Error
RecyclerViewHolder.kt
ImageView を ImageButton に差し替えます。
RecyclerViewHolder.ktimport android.widget.ImageButton val itemImageView: ImageView = view.findViewById(R.id.itemImageView) ↓ val itemImageButton: ImageButton = view.findViewById(R.id.itemImageButton)import 構文は自動挿入です。
自動挿入設定は #4 の記事で行っています。RecyclerAdapter.kt
RecyclerAdapter.ktoverride fun onBindViewHolder(holder: RecyclerViewHolder, position: Int) { holder?.let { it.itemTextView.text = itemList.get(position) } }ImageButton の Image は list_item.xml で直接指定しています。
ここで記載する必要がなかったので消しました。まとめ
今回はここまで。
ボタンは動きませんが、レイアウト追加ができました。
目標到達までまだまだのようです。
冒頭部分で、こんなに記事が長くなるとは思いませんでしたが・・・。成果
- リストに削除ボタンを設置した(イメージ)
参考記事に感謝
たくさんの記事を引用させて頂きました。ありがとうございます。
著者が一部のみを引用したことにより、引用元の意図しない情報として受けられることがないよう、できれば引用元の記事を読んでいただけますようお願いいたします。
またいずれの記事の感想も、著者個人の意見に基づくものですのでご注意ください。本記事で参考にさせて頂いたこちらの記事に、改めて特別な感謝を。
次の記事
#8 Kotlin で TODO アプリを開発・リリースするまでの記録
- 投稿日:2019-08-30T17:42:16+09:00
apkファイル(android)を実機にインストールする方法(ReactNative)
手順
デバイス(OSがandroid)をお使いのコンピュータに接続します。
その後、apkファイルがある場所まで移動し、下記を実行します。adb install sample.apkエラー
$ adb install sample.apk * daemon not running; starting now at tcp:5037 * daemon started successfully error: device unauthorized. This adb server's $ADB_VENDOR_KEYS is not set Try 'adb kill-server' if that seems wrong. Otherwise check for a confirmation dialog on your device.解決法
デバイスをコンピュータから外します。
andoridのSystemsへ移動し、Developer options ->USB debugging
をon,Revoke USB debugging authorizations
をタップします。ターミナルにて、下記コマンドを実行
adb kill-server adb start-server参考
- 投稿日:2019-08-30T16:19:19+09:00
AndroidX + Robolectric + MultiDex のビルドがエラーになるとき
Robolectric の MultiDex 対応に
org.robolectric:shadows-multidex
をいれてて
AndroidX への移行している場合、
ビルド時に Jetifier まわりでエラーが出ることがあります:> Execution failed for JetifyTransform: /home/circleci/.gradle/caches/modules-2/files-2.1/org.robolectric/shadows-support-v4/3.3.2/120e08a6d6d9bd56614f9a3e91c853039107761d/shadows-support-v4-3.3.2.jar. > Failed to transform '/home/circleci/.gradle/caches/modules-2/files-2.1/org.robolectric/shadows-support-v4/3.3.2/120e08a6d6d9bd56614f9a3e91c853039107761d/shadows-support-v4-3.3.2.jar' using Jetifier. Reason: The given artifact contains a string literal with a package reference 'android.support.v4.content' that cannot be safely rewritten. Libraries using reflection such as annotation processors need to be updated manually to add support for androidx.ブラックリストに追加
この場合 Jetifier と相性が悪いので
Workaround としてブラックリスト入りさせる方法が提案されてます:? https://github.com/robolectric/robolectric/issues/4491#issuecomment-498603341
gradle.propertiesandroid.jetifier.blacklist=shadows
ShadowAndroidXMultiDex
を使うように変更あとは
Config
を与えるときのConfig.Builder.setShadows(ShadowMultiDex.class)
をConfig.Builder.setShadows(ShadowAndroidXMultiDex::class)
に変更しておくのも必要です。バージョンによっては
ShadowAndroidXMultiDex
がないことがあるので、shadows-multidex
のバージョンを上げておくことも必要です:app/build.gradletestImplementation "org.robolectric:shadows-multidex:4.3"
GlobalConfigProvider
の設定で、この
Config
を設定するためにGlobalConfigProvider
を設定しておく必要があります:? https://github.com/robolectric/robolectric/issues/4770#issuecomment-479559317
app/src/test/java/your/own/app/provider/CustomGlobalConfigProvider.ktpackage your.own.app.provider import com.google.auto.service.AutoService import org.robolectric.annotation.Config import org.robolectric.pluginapi.config.GlobalConfigProvider import org.robolectric.shadows.multidex.ShadowAndroidXMultiDex @AutoService(GlobalConfigProvider::class) class CustomGlobalConfigProvider: GlobalConfigProvider { override fun get(): Config { return Config.Builder .defaults() .setShadows(ShadowAndroidXMultiDex::class.java) .setPackageName("your.own.app") .build() } }で
AutoService
を使ってるので以下を追加します:app/build.gradletestImplementation "com.google.auto.service:auto-service:1.0-rc6" kaptTest "com.google.auto.service:auto-service:1.0-rc6"これで Robolectric の Multidex が Jetifier 有効でもビルドできるようになるかと思います。
- 投稿日:2019-08-30T10:58:45+09:00
中国でAndroidStudioのハンズオンの準備
ideagearの河野です。
中国でAndroidアプリのハンズオンなどを開催しようとすると、Google関連が遮断されているためいろいろ辛いです。
ここではそういったあれこれをTipsとしてまとめます。
ターゲットは主に Microsoft Windows 10 64bit です。
基本的なツール
Google Chrome
https://google.cn/chrome/ からダウンロードできます
7zip
Windowsに入っているZIP機能は速度が遅かったり長いパスで問題が出たりするのでこれをインストールします。アーカイバはいろいろありますが、ハッシュチェック機能もあるこれを使います。
AndroidStudio
「Windows版Android Studioをzipアーカイブからセットアップする」
https://qiita.com/keicha_hrs/items/070b8f32fc98157541b2
をお手本にしてzip版をダウンロードします。本来は、developer.android.com/studiostudioからダウンロードだけれども、グレートファイアウォールのおかげでアクセスできない。
代わりにhttps://developer.android.google.cnからダウンロード。その他のサイトも見つけましたが・・・
http://www.android-studio.org/
はて。これは何でしょう。ダウンロードできそうですが3.4.1で古そうです。
https://www.androiddevtools.cn/
ここは新しいしダウンロード速度も速かったです。当然、ダウンロードしたものはハッシュタグで正当性をチェックしてください。
セットアップ
Windowsキー+Sを押して、CMDとタイプインしてコマンド画面を呼び出して、そこに表示されているコマンドプロンプトが英数字だけであることを確認します。
もし漢字やスペースなどが入っていたら英数字だけのユーザを作成するか、以下の展開場所を工夫してください。
今回ダウンロードしたのは
Windows (64-bit) android-studio-ide-191.5791312-windows.zip
No .exe installer 723 MB 201328aa7b2593ad538f0cc5d2d98237435d56c89d2bb08f072391de5faaf9f1です。
7-zipでSHA-256をチェックした後展開します。
「Windows版Android Studioをzipアーカイブからセットアップする」
https://qiita.com/keicha_hrs/items/070b8f32fc98157541b2
を元にインストールしていきます。となりましたがCancelを選びました。
コミュニュケーションチャンネル
WeChatアプリ
中国語・日本語・英語が飛び交います。WeChatは翻訳が使いやすいです。また遠隔参加の方もWeChatでコンタクトを取ります。
Slack
Slackは遅いときもありますがおおむね中国国内でも使えます。
Wiki
ハンズオンの情報の集積地としてMediaWikiサーバーを立てました。
サーバはシンガポールリージョンのAWSで用意しました。サーバ連携
クラウドを使うので、AWSに建てたサーバにアクセスします。
putty
からputtyをダウンロード、インストールしてください。
Raspberry Pi
開催場所によってはクラウドサーバへの回線が細かったので、急遽 RaspberryPi をローカルLANに接続してクラウドサーバの代わりとしました。
Android Studio 起動して設定
起動した後も、何かとダウンロードが行われて時間がかかります。ここの説明の分を事前に行っておきます。
最初のプロジェクトをビルド
WorkshopTest2とありますが、実際にはWorkshopTest1としてください。
Workshoptest1:syncing...
と出ています。これが終わるまでしばらく待ちます。
その後、「Error running app No target device found.」と出て止まります。
Kotlinエラーを直す
プロジェクトの設定によっては下記のようにエラーが出ます。
org.gradle.internal.exceptions.LocationAwareException: New Gradle Sync is not supported due to containing Kotlin modules at org.gradle.initialization.exception.DefaultExceptionAnalyser.transform(DefaultExceptionAnalyser.java:99) at org.gradle.initialization.exception.DefaultExceptionAnalyser.collectFailures(DefaultExceptionAnalyser.java:65) at org.gradle.initialization.exception.MultipleBuildFailuresExceptionAnalyser.transform(MultipleBuildFailuresExceptionAnalyser.java:47) at org.gradle.initialization.exception.StackTraceSanitizingExceptionAnalyser.transform(StackTraceSanitizingExceptionAnalyser.java:29) at org.gradle.initialization.DefaultGradleLauncher.finishBuild(DefaultGradleLauncher.java:174) at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:165) at org.gradle.initialization.DefaultGradleLauncher.executeTasks(DefaultGradleLauncher.java:134) at org.gradle.internal.invocation.GradleBuildController$1.execute(GradleBuildController.java:58) at org.gradle.internal.invocation.GradleBuildController$1.execute(GradleBuildController.java:55) at org.gradle.internal.invocation.GradleBuildController$3.create(GradleBuildController.java:82) at org.gradle.internal.invocation.GradleBuildController$3.create(GradleBuildController.java:75) at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:183) at org.gradle.internal.work.StopShieldingWorkerLeaseService.withLocks(StopShieldingWorkerLeaseService.java:40) at org.gradle.internal.invocation.GradleBuildController.doBuild(GradleBuildController.java:75) at org.gradle.internal.invocation.GradleBuildController.run(GradleBuildController.java:55) at org.gradle.tooling.internal.provider.runner.ClientProvidedPhasedActionRunner.run(ClientProvidedPhasedActionRunner.java:60) at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35) at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35) at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:58) at org.gradle.tooling.internal.provider.ValidatingBuildActionRunner.run(ValidatingBuildActionRunner.java:32) at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:39) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:51) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:45) at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416) at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:45) at org.gradle.launcher.exec.InProcessBuildActionExecuter$1.transform(InProcessBuildActionExecuter.java:49) at org.gradle.launcher.exec.InProcessBuildActionExecuter$1.transform(InProcessBuildActionExecuter.java:46) at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:78) at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:46) at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:31) at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:42) at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:28) at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:78) at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:52) at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:59) at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:36) at org.gradle.tooling.internal.provider.SessionScopeBuildActionExecuter.execute(SessionScopeBuildActionExecuter.java:68) at org.gradle.tooling.internal.provider.SessionScopeBuildActionExecuter.execute(SessionScopeBuildActionExecuter.java:38) at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:37) at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:26) at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:43) at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:29) at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:60) at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:32) at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:55) at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:41) at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:48) at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:32) at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:67) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:37) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74) at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72) at org.gradle.util.Swapper.swap(Swapper.java:38) at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:62) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:81) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50) at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:295) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46) at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55) Caused by: com.android.tools.idea.gradle.project.sync.ng.NewGradleSyncNotSupportedException: New Gradle Sync is not supported due to containing Kotlin modules at com.android.tools.idea.gradle.project.sync.ng.SyncProjectModels.failIfKotlinPluginAppliedAndKotlinModelIsMissing(SyncProjectModels.java:131) at com.android.tools.idea.gradle.project.sync.ng.SyncProjectModels.failIfKotlinPluginAppliedAndKotlinModelIsMissing(SyncProjectModels.java:136) at com.android.tools.idea.gradle.project.sync.ng.SyncProjectModels.populate(SyncProjectModels.java:88) at com.android.tools.idea.gradle.project.sync.ng.SyncAction.execute(SyncAction.java:59) at com.android.tools.idea.gradle.project.sync.ng.SyncAction.execute(SyncAction.java:33) at org.gradle.tooling.internal.consumer.connection.InternalBuildActionAdapter.execute(InternalBuildActionAdapter.java:80) at org.gradle.tooling.internal.provider.runner.ClientProvidedPhasedActionRunner$ActionRunningListener.runAction(ClientProvidedPhasedActionRunner.java:120) at org.gradle.tooling.internal.provider.runner.ClientProvidedPhasedActionRunner$ActionRunningListener.run(ClientProvidedPhasedActionRunner.java:110) at org.gradle.tooling.internal.provider.runner.ClientProvidedPhasedActionRunner$ActionRunningListener.projectsEvaluated(ClientProvidedPhasedActionRunner.java:98) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) at org.gradle.internal.event.DefaultListenerManager$ListenerDetails.dispatch(DefaultListenerManager.java:376) at org.gradle.internal.event.DefaultListenerManager$ListenerDetails.dispatch(DefaultListenerManager.java:358) at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:58) at org.gradle.internal.event.DefaultListenerManager$EventBroadcast$ListenerDispatch.dispatch(DefaultListenerManager.java:346) at org.gradle.internal.event.DefaultListenerManager$EventBroadcast$ListenerDispatch.dispatch(DefaultListenerManager.java:333) at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:42) at org.gradle.internal.event.BroadcastDispatch$SingletonDispatch.dispatch(BroadcastDispatch.java:230) at org.gradle.internal.event.BroadcastDispatch$SingletonDispatch.dispatch(BroadcastDispatch.java:149) at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:58) at org.gradle.internal.event.BroadcastDispatch$CompositeDispatch.dispatch(BroadcastDispatch.java:324) at org.gradle.internal.event.BroadcastDispatch$CompositeDispatch.dispatch(BroadcastDispatch.java:234) at org.gradle.internal.event.ListenerBroadcast.dispatch(ListenerBroadcast.java:140) at org.gradle.internal.event.ListenerBroadcast.dispatch(ListenerBroadcast.java:37) at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93) at com.sun.proxy.$Proxy13.projectsEvaluated(Unknown Source) at org.gradle.initialization.DefaultGradleLauncher$NotifyProjectsEvaluatedListeners.run(DefaultGradleLauncher.java:407) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31) at org.gradle.initialization.DefaultGradleLauncher.projectsEvaluated(DefaultGradleLauncher.java:428) at org.gradle.initialization.DefaultGradleLauncher.access$1400(DefaultGradleLauncher.java:50) at org.gradle.initialization.DefaultGradleLauncher$ConfigureBuild.run(DefaultGradleLauncher.java:305) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31) at org.gradle.initialization.DefaultGradleLauncher.configureBuild(DefaultGradleLauncher.java:210) at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:151) ... 75 moreと出ています。
「File」-「Settings」-「Kiitlin」の開くと「A new version ・・・・」と出ているので「Install」とします。
Installが終わったら一度AndroidStudioを終了してもう一度起動しなおしたら治りました。ADV(エミュレーター)を用意
PCのメモリが8GBytes以上ある場合は、エミュレーターを使えるようにしておきます。
「tools」-「AVD Manager」で設定します。「+ Create Virtual Device...」を押します
Pixel 2を選ぶことにします。
8.1のOreoを選ぶことにしましたが、一番最新のものでも良かったかも知れません。「Download」を選びます。
ダウンロードに時間がかかります。その後続けていくとADV設定が完了し、エミュレーターが起動します
エミュレーターは最初の起動は時間がかかります。
実行できました。
実機を接続する
USBケーブルを用意し、Android実機を接続します。
「開発者向けオプション」で「USBデバッグ」を有効にします。
Android 8.0以降の場合は、設定画面から「システム」-「端末情報」-「ビルド番号」を7回タップすると「システム」-「開発者向けオプション」が表示されるようになる。
英語メニューの場合は、設定画面から[System]- [About phone]- [Build number] を 7 回タップすると、[System]- [Developer options] が表示されるようになる。
Android8.0未満の場合は、機種ごとに違うので、要調査。
このような表示になった場合は、プロジェクトのSDKバージョンの設定に比べて実機のAndroidバージョンが低いために起こっています。
この場合はエミュレーターを使って開発するか、以下のようにSDKのバージョンを適宜ダウンロードし、プロジェクトを作り直します。
開発を始めてから
ビルド時に、gradleがsyncのためにインターネット接続を行うので、回線が遅い場合はgradleをオフラインモードに変更しておくのがいいかもしれません。
「File」-「Settings」-「Build,Excusion,Deployment」-「Gradle」の「Offline work」にチェックを入れます。
- 投稿日:2019-08-30T10:10:44+09:00
Firebase Test Labのcloudtestingscreenshotter_libでスクリーンショット名に日本語を使ったらダメだった件
Firebase Test Labでスクリーンショットを撮るために cloudtestingscreenshotter_lib というライブラリが提供されています。(ライブラリのDL、導入方法などは下記公式ページへ→ Firebase Test Lab インストゥルメンテーション テストのスクリーンショットを作成する)
ScreenShotter.takeScreenshot("main_activity", activity)↑のようなコードでスクリーンショットを撮ることができるのですが、引数で指定しているスクリーンショット名(上記のコードでは
"main_activity"
)に日本語を使ったらダメだったというお話です。何故かテストが「不確定」となって終わってしまう
Firebase Test Labを定期実行させているのですが、いつぞやのタイミングから「不確定」というステータスでテストが終わってしまうようになりました。
CI上のログから ERROR: (gcloud.firebase.test.android.run) Firebase Test Lab infrastructure failure: Exhausted test run attempts というエラーメッセージが出ており、Freeプランで使っているから何か制限をオーバーしたのかな?と思ったりしたので、数日様子見。
しかし数日経っても状況は変わらずで、Consoleからもこれ以上の情報を得ることができず、途方にくれてました。Firebase Slackコミュニティで質問してみた
どうしようもないので、「明確な結果が得られずお困りの場合は、Firebase Slack コミュニティの #test-lab チャンネルにご参加ください。」 とあったのでSlackで質問してみました。
Firebase Community Slackには、各サービスごとにチャンネルがあり、そこの #test-lab で質問をしました。
内容としては
ERROR: (gcloud.firebase.test.android.run) Firebase Test Lab infrastructure failure: Exhausted test run attempts
というエラーが出てしまっています。フリープランで使ってるけど、上限はオーバーしてないんだけどみたいな感じです。(ちなみにめっちゃ拙い英語で送りました)
Googlerから返信が来た
1日もしないうちに返信が来ました。
内容としては「スクリーンショット名をasciiにして、もっかい試してほしい」
みたいな感じで、
This is the error we see on our side: (エラー文)
とFirebase側のエラーの内容も添付してくれました。(SlackのDM)エラーの内容を見ると、いつぞやのタイミングで追加したテストで、スクリーンショット名に日本語が含まれているやつが原因っぽいことがわかりました。
スクリーンショット名はASCII文字で
すぐさまスクリーンショット名に日本語を指定しているところを直して、Firebase Test Labでテストを走らせたら、問題なく実行されました。
スクリーンショット名には日本語など含ませず、ASCII文字でやる必要がある ということがわかりました。まとめ
cloudtestingscreenshotter_lib
でスクリーンショットを撮るときは、スクリーンショット名に日本語を指定してるとダメだった- FirebaseでわからないことがあったらSlackで質問をするとGooglerが返信してくれる
- 投稿日:2019-08-30T05:25:03+09:00
AndroidのIMEI取得
echo "[device.imei]: [$(adb shell service call iphonesubinfo 1 | awk -F "'" '{print $2}' | sed '1 d'| tr -d '\n' | tr -d '.' | tr -d ' ')]"
- 投稿日:2019-08-30T01:44:06+09:00
[SQLite] Cursorで起こるIllegalStateException
私が開発したアプリ KUMIWAKE のユーザー様から以下のようなお問い合わせをいただきました。
以前まで普通に使えていましたが、メンバーを選んだり組分けしようとすると「問題が発生したためkumiwakeを終了します」のと出ます。どうすればよいですか?
はい…完全にこちらの不手際でユーザー側ではどうにもできないので至急アップデートにて対応させていただきました。最新ver.でなぜかクラッシュが多かったのでこういったご意見は本当に助かります。
エラーの原因
しかし、ここで困ったことが1つ。
自分の環境ではエラーが再現できないのです。実機もAVDもだめ。Play Consoleのスタックトレースを見ると以下のようにありました。
java.lang.IllegalStateException: at android.database.CursorWindow.nativeGetString (CursorWindow.java) at android.database.CursorWindow.getString (CursorWindow.java:438) at android.database.AbstractWindowedCursor.getString (AbstractWindowedCursor.java:51) ...調べてみるとデータベースのCursorによるエラーのようでした。
以前は機能していたようなので、Cursor部分の変更履歴を見直して何とか原因を特定しました。
c.getString(c.getColumnIndex(COL_NAME))
←この部分ですhttps://codeday.me/jp/qa/20190421/668862.html
こちらの方の回答にあるようにgetColumnIndex(COL_NAME)
がCOL_NAMEのIndexを見つけられず、-1を返していたようです。それによってc.getString(-1)
となり、カラムが見つからない!とエラーを吐いたわけですね。(カラム番号は0~)解決策
とりあえずは以前の状態を復元するために
getColumnIndex()
を使わない方向で落ち着きました。(分かりやすいので本当は使いたいですが...)修正前:
c.getString(c.getColumnIndex(COL_NAME))
修正後:c.getString(1)
直接カラム番号を指定しました。
修正後は正常に動作したようです。めでたしめでたし。
getColumnIndex(COL_NAME)
を使いたい場合は、カラムが見つからないときに-1が返されてしまうので、こちらの記事にあるようにgetColumnIndexOrThrow(COL_NAME)
を使うのが良さそうです。疑問は残る
https://teratail.com/questions/128793
同じような問題で悩んでいる方がおられました。この方の質問にあるように端末によってgetColumnIndex()
がうまく値を返す場合と返さない場合があるようです。Androidのバージョンには依存していなかったので、端末の問題なのか...
SQLiteまわりの詳しい方おられましたらご教授をお願いします。(泣)参考
- 投稿日:2019-08-30T00:42:59+09:00
Flutterウィークリー #73
Flutterウィークリーとは?
FlutterファンによるFlutterファンのためのニュースレター
https://flutterweekly.net/この記事は#73の日本語訳です
https://mailchi.mp/flutterweekly/flutter-weekly-73※Google翻訳を使って自動翻訳を行っています。翻訳に問題がある箇所を発見しましたら編集リクエストを送っていただければ幸いです。
読み物&チュートリアル
Flutterチュートリアル:従来のショッピングアプリUIをフラッターで簡単に作成
https://cybdom.tech/flutter-tutorial-shopping-app-ui/
Flutter Inを使用したFlutter GridViewチュートリアル
https://www.gotut.net/flutter-grid-view-tutorial/
FlutterのGridviewを使用して、フェードイン効果のある画像ギャラリーを作成する方法を学びます。Flutter電卓アプリを構築する
https://itnext.io/building-a-calculator-app-in-flutter-824254704fe6
Kenneth Reillyは、 Flutter段階的に電卓を作成します。Flutter iOSアプリのキーボード完了ボタンUX
https://blog.usejournal.com/keyboard-done-button-ux-in-flutter-ios-app-3b29ad46bacc
Ramankit Singhは、iOSのキーボードで[完了]ボタンを再現するソリューションを示しています。ストリームを使用したFlutterでの非同期プログラミング
https://medium.com/@bertoboh/async-programming-in-flutter-with-streams-c949f74c9cf9
Albert ObohによるFlutterでのStreamsの使用の概要Flutter認証
https://medium.com/@greg.perry/auth-in-flutter-97275b29b550
Greg Perryは、Firebase authでauthパッケージを使用する方法を詳細に分析して示します。FlutterとCustom Painterを使用してレーダーチャートを作成する
https://medium.com/@d.panaite92/building-a-radar-chart-with-flutter-and-custom-painter-384c005002f9
Dan Panaiteによるこのチュートリアルで、カスタムペインターを使用して独自のレーダーチャートを作成する方法を学びます。Flutter for the Web — Githubにデプロイする
https://medium.com/flutter-community/flutter-for-the-web-deploy-to-github-da454e4bc079
Flutter webを使用していますか?アコラ・イングのおかげで、あなたの作品を世界に見せてください。 DKB。GithubPagesにデプロイする方法を教えてくれます。Flutter iOSアプリのアイコンをプログラムで変更する
https://medium.com/flutter-community/programatically-change-ios-app-icon-in-flutter-c9e84bc541a2
iOS 10.3以降、Appleはアプリのランチャーアイコンをプログラムで変更する機能を導入しました。 Alessandro FaveroはFlutterからそれを行う方法を説明しています。MVCの神社
https://medium.com/flutter-community/shrine-in-mvc-7984e08d8e6b
MaterialサンプルアプリShrineを知っていますか? Greg Perryが、サンプルを取得してMVCアーキテクチャに変更する方法を説明します。プロバイダーとBLoCでFlutter状態管理を簡素化
https://medium.com/fluttervn/simplify-flutter-state-management-with-provider-and-bloc-dcfad49bedf2
ラムはプロバイダーライブラリをテストしており、いくつかの問題を見つけた後、プロバイダーとBLoCの組み合わせがどのようにうまく機能するかを説明します。Flutterネットワークリクエストをデバッグする3つの簡単な方法
Flutter作業するときにネットワーク要求をデバッグするのに役立ついくつかのヒント。Flutterレスポンシブデザイン:はじめに
https://www.raywenderlich.com/4324124-responsive-design-for-flutter-getting-started
JB Lorenzoは、 Flutterさまざまな画面サイズと向きを処理する方法に関する洞察を提供します。ビデオ&メディア
Flutter TDDクリーンアーキテクチャコース
https://www.youtube.com/watch?v=KjE2IDphA_U&feature=youtu.be&t=2s
コードをクリーンに保ち、テストすることは、2つの最も重要な開発プラクティスです。 Clean ArchitectureをFlutterプロジェクトに適用する方法を学びます。Flutter UI | Stadiaアプリのコンセプト
https://www.youtube.com/watch?v=-rqvZfUdSPw&feature=youtu.be&t=6395s
このビデオでは、CustomPainter、カスタムウィジェット、アニメーション、その他を使用して、レスポンシブで適応性のあるレイアウトを作成する方法を説明します。Flutterアニメーション切り替えボタン
https://www.youtube.com/watch?v=XI3LFEvagBY&feature=youtu.be&t=610s
アニメーション付きのカスタムスイッチボタンを作成する方法を学びます。Flutter Desktopの使用開始
https://www.youtube.com/watch?v=V09e5nb95lo&feature=youtu.be&t=236s
このビデオでは、 Flutterを使用してデスクトップアプリケーションを作成するための最初の手順を実行する方法を示します。AdmobをFlutterに追加する方法
https://www.youtube.com/watch?v=xSrNB6ge66Q&feature=youtu.be&t=205s
firebase_admob dartパッケージを使用してフラッターにadmobを追加する方法に関するビデオチュートリアルのコーディングセマンティクス(今週のFlutterウィジェット)
https://www.youtube.com/watch?v=NvtMt_DtFrQ&list=PLjxrf2q8roU23XGwz3Km7sQZFTdB996iG&index=48
Semanticsを使用して、アプリのUIにウィジェットに関する情報を注釈するウィジェットを使用して、 Flutterアプリをより包括的にします。ライブラリ&コード
henriquearthur / flutter_native_splash
https://github.com/henriquearthur/flutter_native_splash
AndroidおよびiOSでスプラッシュスクリーンを追加するためのネイティブコードを自動的に生成します。特定のプラットフォーム、背景色、スプラッシュ画像でカスタマイズします。
ketanchoyal / extended_navbar_scaffold
https://github.com/ketanchoyal/extended_navbar_scaffold
拡張可能なフローティングナビゲーションバーを備えたカスタム拡張足場
simformsolutions / flutter_showcaseview
https://github.com/simformsolutions/flutter_showcaseview
iOSおよびAndroidで機能を紹介できるFlutterプラグイン。