20210412のAndroidに関する記事は10件です。

【Android】Espressoでの非同期テストでIdlingResourceを使用する

Espressoで非同期テストのやり方を学んだのでメモ IdlingResource Espressoで非同期な処理を使用したUIテストを実施するときは、安易にsleepとか使用せずに、IdlingResourceを使うことが推奨されているようです。 IdlingResource自体はインタフェースなので、実際にはIdlingResourceを実装したクラスが必要になりますが、標準でいくつか用意されており今回は一番スタンダードなCountingIdlingResourceを使用します。 アクティブなタスクのカウンタを保持します。カウンタがゼロの場合、関連するリソースはアイドリング状態であると見なされます。この機能は、Semaphore の機能によく似ています。テスト中にアプリの非同期操作を管理するには、通常はこの実装で十分です。 アイドルリソース使用の流れ アイドルリソース使用の流れは以下になります。 テスト前にアイドルリソースを登録する 非同期処理開始前にアイドルリソースがビジーであることをセットする 非同期処理完了時点でアイドルリソースがアイドルであることをセットする テスト終了後にアイドルリソースを登録解除する。 一般的には、1は@Beforeで実施し、4は@Afterで実施するようです。 テスト設計 今回やりたいテストの流れについて設計します。 「ProgressBar」「include」「WebView」の各コンポーネントが初期表示時は「Progress」のみ表示されていて、ページ読み込み完了し、Webページが表示できる直前で「WebView」のみ表示されるようになるよね?といった部分を確認するテストになります。 今回は、このうち「ページ読み込み完了」という部分が非同期でいつ完了になるのかわかりません。よって、アイドルリソースを使って「読み込み完了したよ!」ということをEspressoに教えてあげます。 テスト実装 設計に基づいて実装をおこないます。 まず、テスト対象のフラグメントに手を加えます。 public class TosViewFragment extends Fragment implements AppWebViewClientCallback { @VisibleForTesting private final CountingIdlingResource countingIdlingResource = new CountingIdlingResource("WebViewIdlingResource"); @VisibleForTesting(otherwise = VisibleForTesting.NONE) public IdlingResource getCountingIdlingResource() { return countingIdlingResource; } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { // ビジー状態 countingIdlingResource.increment(); // 省略 // Viewの返却 return binding.getRoot(); } @Override public void onPageCommitVisibleHandle(boolean isOk) { // プログレスバーを非表示にする binding.scTovPbProgressBar.setVisibility(View.GONE); if (isOk) { // ページ表示可 // Webページを表示する binding.scTovWvTos.setVisibility(View.VISIBLE); } else { // Sorryページを表示する binding.scTovInSorry.setVisibility(View.VISIBLE); } // アイドル状態 countingIdlingResource.decrement(); } } ? CountingIdlingResourceのインスタンスを対象のフラグメントに生成します。(ゲッターとかはテストクラスからしか呼ばれないので@VisibleForTesting(otherwise = VisibleForTesting.NONE)をつけています。) インスタンスを生成するときに、リソース名を引数にします。 つぎに、onCreateViewでビジー状態にしています。CountingIdlingResourceは内部でカウンタを持っており、ゼロになるとアイドル状態とみなされるので#incrementでカウンタをインクリメント(つまり、ビジー状態)にします。 最後に、onPageCommitVisibleHandle(WebViewClient#onPageCommitVisibleが呼ばれた時のコールバック処理)の最後で#decrementしてあげて差し引き0(つまりアイドル状態)にしてあげます。 次にテストクラスに手を加えます。私はページオブジェクトが好きなので、ページオブジェクトで実装しています。 @LargeTest @RunWith(AndroidJUnit4.class) public class ScT_ScTov { public ActivityScenario<MainActivity> scenario; private IdlingResource idlingResource; @Before public void setUp() { // アクティビティの起動 scenario = ActivityScenario.launch(MainActivity.class); } @After public void tearDown() { // アイドルリソースの登録解除 IdlingRegistry.getInstance().unregister(idlingResource); } @Test public void ScreenTest_ScTov() { startScreenTest() .isNotDisplayedScTovWbTos() // WebViewが表示されていないこと .isDisplayedScTovPbProgressBar() // ProgressBarが表示されていること .isNotDisplayedScTovInSorry(); // includeが表示されていないこと registerIdlingResource() // アイドルリソースを登録 .isDisplayedScTovWbTos() // WebViewが表示されていること .isNotDisplayedScTovPbProgressBar() // ProgressBarが表示されていないこと .isNotDisplayedScTovInSorry() // includeが表示されていること ; } @NonNull private ScTovPO startScreenTest() { return new ScManPO() .clickHamburgerMenu() // ハンバーガーメニュー_押下 .clickTosViewMenuItem(); // 利用規約・免責事項メニューアイテム_押下 } private ScTovPO registerIdlingResource() { scenario.onActivity(activity -> { // TosViewFragment取得 TosViewFragment tosViewFragment = (TosViewFragment) Objects.requireNonNull(activity .getSupportFragmentManager() .findFragmentById(R.id.sc_man_fc_nav_host)) .getChildFragmentManager() .getFragments() .get(0); // アイドルリソース取得 idlingResource = tosViewFragment.getCountingIdlingResource(); // アイドルリソースを登録 IdlingRegistry.getInstance().register(idlingResource); }); return new ScTovPO(); } } ? 今回色々試してみましたが、上記のような形で成功しました。 処理の流れは以下の通りです。 setUpでアクティビティを起動 ScreenTest_ScTovでUIテスト開始 startScreenTestでアクティビティから対象画面への遷移操作を実施 ScreenTest_ScTovの途中で「アイドルリソースの登録」を行う。 アイドルリソースをフラグメントから取得し登録する。 テスト終了後、tearDownでアイドルリソースの登録解除 4,5は#registerIdlingResourceでやっています。アクティビティからフラグメントを取得し、ゲッターを介して取得したものをレジストしています。 テスト評価 Espressoを使ってUIテストを実施します。 Testing started at 10:04 PM ... 04/12 22:04:00: Launching 'ScreenTest_ScTov()' on Pixel 2 API 28 (SmartPhone). App restart successful without re-installing the following APK(s): androidx.test.orchestrator, androidx.test.services Running tests 無事テストが成功したことがわかります。 IdlingResourceを使えば、Espressoでの非同期テストも簡単に評価することができました。 めでたしめでたし。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

URLSchemeのインテントをadbで実行する時に複数パラメータを渡す方法

adbでURLScheme起動する際、複数のパラメータを渡す必要があって困ったのでメモ adbでURLScheme起動を行う方法 adb shell am start -a android.intent.action.VIEW -d "{URL}" URLSchemeにパラメータを1つ渡す方法 adb shell am start -a android.intent.action.VIEW -d "{URL}?{KEY}={VALUE}" URLSchemeにパラメータを複数渡す方法 adb shell am start -a android.intent.action.VIEW -d "{URL}?{KEY}={VALUE}\&{KEY}={VALUE}" adb shell am start -a android.intent.action.VIEW -d '"{URL}?{KEY}={VALUE}&{KEY}={VALUE}"'
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

古いAndroidスマホ/タブレットで、GeforceNowを使ってAPEXがプレイできるのかを検証してみた

【本記事のテーマ】 FPSゲームで人気のAPEXを、古い型落ちAndroidタブレットでプレイできないか検証してみた。 【用意したモノ】 ・GeforceNowアカウント(月額2000円弱) ・ホリ製のUSB接続ゲームパッド(3500円程度)  HORI ホリ ホリパッド for Nintendo Switch スーパーマリオ NSW-188 ・ファーウェイ製のAndroidタブレット  Huawei MediaPad T2 Pro 606HW ・OTGケーブル(700円程度) 【2個入り】NIMASO USB C 変換 アダプタ ( Type C - USB 3.0 メス ) 20CM OTGケーブル タイプC 変換コネクター 【筆者の概況】 筆者はAPEX歴3ヶ月のペーペーど素人。シルバーランクからゴールドに上がれないでもがき苦しんでいる。 以前いた職場の同期から、APEXを一緒にやろうとゴリ押しされ、始めようとする。 しかし、直近は仮想通貨マイニングの影響でグラボが高騰しており、お金のない私はゲーミングPCを用意できなかった。 仕方がないのでGeforceNowでひとまず凌ぎ、お金に余裕ができたらゲーミングPCを買うことにした。 【構築環境の様子画像】 【プレイしてみた結果】 【】
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Koinで2つ以上のインターフェイスを継承しているクラスを注入する方法

interface SampleA interface SampleB class SampleImpl : SampleA, SampleB インターフェイスSampleA、SampleBを継承しているSampleImplをKoinで注入します。 val modules = module { // 1つのinterface(SampleA)を継承している場合。 factory<SampleA> { SampleImpl() } // 2つ以上のinterface(SampleA/SampleB)を継承している場合。 factory { SampleImpl() }.binds(SampleA::class, SampleB::class) } startKoin { androidContext(context) modules(modules) }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Android】selector内の画像サイズを指定

少し詰まったので自分用メモ drawable内のxmlファイルでselector内の画像サイズを指定するには、<item>内に<layer-list>, <item>を作成してwidth, height, drawableを指定する。 <selector>直下の<item>にwidth, heightを指定しても私の環境では反映されなかったので注意 (drawableは反映された)。 smple.xml <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <!--ここでwidth, heightを指定しても反映されない--> <item android:state_checked="false"> <layer-list> <!--ここでwidth, heightを指定--> <item android:width="20dp" android:height="10dp" android:drawable="@drawable/icon_off"/> </layer-list> </item> <item android:state_checked="true"> <layer-list> <item android:width="20dp" android:height="10dp" android:drawable="@drawable/icon_on"/> </layer-list> </item> </selector>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Flutter×FirebaseでPJ始めるときにやること色々

FirebaseとFlutterを用いて開発することが多いのですが、毎回リリース直前になってFLAVORを分けたくなったり、セキュリティルールを検討し始めたりしてしまいます。 とくに複数人で開発していると、FLAVOR分けは他の人の開発の手を止めてしまう原因にもなってしまいますので、この辺の初期設定を脳死で出来るように手順化しておきます。 筆者は普段からWindowsとMacOSの両方で開発していますが、iOSのリリースも考えているなら、Macで全てやってしまうのがいいと思います。 今回使用したリポジトリは以下です。 この記事でやってること FirebaseプロジェクトをFlavor毎(Development/Production)に作成し、Flutterプロジェクトと紐づける セキュリティルールやCloud Functions、Hostingのための環境構築をDockerで行う LPやプライバシーポリシーをデプロイするためのFirebase Hostingの設定 Lint(pedantic)の導入方法 Flutter SDKのバージョン固定(fvmを使用) 筆者の環境 Windows > flutter doctor Doctor summary (to see all details, run flutter doctor -v): [√] Flutter (Channel stable, 1.22.5, on Microsoft Windows [Version 10.0.19041.867], locale ja-JP) [√] Android toolchain - develop for Android devices (Android SDK version 30.0.1) [!] Android Studio (version 4.1.0) X Flutter plugin not installed; this adds Flutter specific functionality. X Dart plugin not installed; this adds Dart specific functionality. [!] VS Code (version 1.54.3) X Flutter extension not installed; install from https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter [!] Connected device ! No devices available ! Doctor found issues in 3 categories. MacOS Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel stable, 1.22.4, on macOS 11.2.3 20D91 darwin-x64, locale ja-JP) [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2) [✓] Xcode - develop for iOS and macOS (Xcode 12.4) [!] Android Studio (version 4.1) ✗ Flutter plugin not installed; this adds Flutter specific functionality. ✗ Dart plugin not installed; this adds Dart specific functionality. [!] VS Code (version 1.53.0) ✗ Flutter extension not installed; install from https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter [!] Connected device ! No devices available ! Doctor found issues in 3 categories. 事前準備 以下のことを事前に行っている前提で進めます Firebaseのスキーマ設計 Android StudioとXCodeのインストールおよびFlutterでの環境構築 VSCodeのインストール(Flutter extensionsは必須ではない) Android StudioからFlutterプロジェクト作成 Dockerが使える環境が整っている ※プロジェクト作成時にパッケージ名を決めるが、com.example のドメインは予め避けておいたほうが良い。自分が取得しているドメイン名や、GitHubのドメイン名(io.github.<ユーザー名>)に変更しておく。 また、このパッケージ名は設定を行う際によく使用するので控えておく。Firebaseに登録する際に躓かないように、英字、数字、ピリオドのみを使用して決めておく方が良い(_アンダースコアと-ハイフンはそれぞれiOSなら_、Androidなら-が使用不可なので、OS毎に別のパッケージ名となってしまうことに注意する) 今回はDevelopmentという開発環境と、Productionという本番環境の2環境を用意することにする。 Flavorごとのビルド設定 主に以下を参考に手順化しました。本記事では解説は行わないので、理由が知りたくなったらご参考ください。 環境設定 - KosukeSaigusa/recipe-app Flutterで環境ごとにビルド設定を切り替える — iOS編 - medium iOS側の設定 open ios/Runner.xcworkspaceでXCodeからプロジェクトを開く Runner>PROJECT>RunnerのDeployment Targetを10.0以上に変更しておく(現在のfirebase_coreのバージョンだと、ここが低いとビルドに失敗する) XCodeのRunnerの部分をクリックし、Manage Schemes...をクリックする 出てきた画面の左下の「+」をクリックしてTarget,Nameが以下のようなものを追加する Target Name Runner Development Runner Production 次にRunner>PROJECT>RunnerのConfigurationの下部の「+」をクリックし、設定を追加する。 Duplicate "Debug" ConfigurationをクリックしてDebug-Developmentを追加し、Duplicate "Release" ConfigurationをくりっくしてRelease-Productionを追加する。 次に左ペインで右クリックしNew File...をクリックする。Configuration Setting Fileを選択し、NEXTをクリックする。 Configuration Setting Fileの内容は以下の通り。2回繰り返す。 ファイル名 保存場所 Group Target Development.xcconfig ios/Flutter Flutter Runnerにチェック Production.xcconfig ios/Flutter Flutter Runnerにチェック Debug-Development.xcconfig ios/Flutter Flutter Runnerにチェック Release-Production.xcconfig ios/Flutter Flutter Runnerにチェック 各ファイルを以下のように編集する Development.xcconfig FLUTTER_FLAVOR=Development PRODUCT_BUNDLE_IDENTIFIER=<パッケージ名>.development DISPLAY_NAME=<開発環境のアプリ名> FLUTTER_TARGET=lib/main.dart Production.xcconfig FLUTTER_FLAVOR=Production PRODUCT_BUNDLE_IDENTIFIER=<パッケージ名> DISPLAY_NAME=<アプリ名> FLUTTER_TARGET=lib/main.dart Release-Production.xcconfig #include "Release.xcconfig" #include "Production.xcconfig" Debug-Development.xcconfig #include "Debug.xcconfig" #include "Development.xcconfig" Runner>PROJECT>RunnerのConfigurationsを以下のように設定します。 その後、Runner > PROJECT > Runner > Build Settings > Packaging の中の Product Bundle Identifierを以下のように、正しいパッケージ名を設定しておきます。 Runner > TARGET > Runner も同様に設定しておく。 次にAndroid Studioからinfo.plistを開き最後の行(</dict>と</plist>)の手前に以下を追記する。 info.plist <key>FlutterFlavor</key> <string>$(FLUTTER_FLAVOR)</string> <key>CFBundleDisplayName</key> <string>$(DISPLAY_NAME)</string> XCodeに戻り、Runner>Runner>Info.plistをクリックし、Bundle nameをリリースする際のアプリ名に変更する。(これはリリース前に行っても良い) FirebaseのGoogleService-Info.plistを追加する前に先に設定を行う。 Runner>Runnerで右クリックし、New Groupをクリック 名前をFirebaseとしておく Runner > Targets > Runner > Build Phases を開きNew Run Script Phaseをクリックする 作成されたRun Scriptをダブルクリックし、適当な名前に変更しておく(例えばRun Script for Firebase) 以下をコピーしてスクリプト欄に貼り付ける。 if [[ "${CONFIGURATION}" == "Debug-Development" ]]; then rm $PRODUCT_NAME/GoogleService-Info.plist cp $PRODUCT_NAME/Firebase/GoogleService-Info-Development.plist $PRODUCT_NAME/GoogleService-Info.plist echo "GoogleService-Info-Production.plist copied." elif [[ "${CONFIGURATION}" == "Release-Production" ]]; then rm $PRODUCT_NAME/GoogleService-Info.plist cp $PRODUCT_NAME/Firebase/GoogleService-Info-Production.plist $PRODUCT_NAME/GoogleService-Info.plist echo "GoogleService-Info-Production.plist copied." elif [[ "${CONFIGURATION}" == "Release" ]]; then rm $PRODUCT_NAME/GoogleService-Info.plist cp $PRODUCT_NAME/Firebase/GoogleService-Info-Production.plist $PRODUCT_NAME/GoogleService-Info.plist echo "GoogleService-Info-Production.plist copied." else echo "configuration didn't match to Development, Staging or Production" echo $CONFIGURATION exit 1 fi また、Output Fileに$SRCROOT/Runner/GoogleService-info.plistを追加しておく。 Android側の設定 android/app/build.gradle buildTypes { debug { debuggable true // 後の鍵の設定のために追加。現状はコメントアウトしておく // signingConfig signingConfigs.debug } release { // 後の鍵の設定のために追加。現状はコメントアウトしておく // signingConfig signingConfigs.release } } flavorDimensions "app" productFlavors { development { dimension "app" resValue "string", "app_name", "<開発環境のアプリ名>" applicationIdSuffix ".development" } production { dimension "app" resValue "string", "app_name", "<本番環境のアプリ名>" } } Android Studioでのbuild構成の編集 この項目は複数人での開発を行う場合には全員が行う必要がある項目です。 下図の「構成の編集」をクリックします 出てきたダイアログの左上にある「+」をクリックし、新規構成の追加からFlutterを選択します。 すでに存在するmain.dartのDart entrypointをコピーして新規作成した名称未設定のDart Entrypointにペーストします。 以下のように設定します。 名前(Name) 追加引数(Additional Arguments) Build flavor Debug-Development --debug --flavor development --dart-define=FLAVOR=development development Release-Production --release --flavor production --dart-define=FLAVOR=production production Firebase Projectの作成 Firebase ProjectをFlavor毎に作成します。 プロジェクト名-dev、プロジェクト名-prod などと分けておくとわかりやすいです。 iOSアプリの追加 下図のiOSをクリックします。 dev側はiOSのバンドルIDをパッケージ名.development、本番側はパッケージ名を入力し、アプリのニックネームはわかりやすい名前を入力しておきます。 アプリを登録 をクリックすると、GoogleService-Info.plistをダウンロードできるので、GoogleService-Info-Development.plistにリネームし、XCodeから Runner>Runner>Firebaseへコピーする 本番環境もプロジェクトを作成し、同様にiOSアプリを追加し、GoogleService-Info.plistをダウンロードしたのちに、GoogleService-Info-Production.plistにリネームし、XCodeから Runner>Runner>Firebaseへコピーしておく。 この時点でAndroid StudioからiOSでDebug-Developmentでデバッグビルドできることを確認しておく。 Androidアプリの追加 同様にしてAndroidアプリも追加しておく。 Androidパッケージ名を、dev側はパッケージ名.development、本番側は単にパッケージ名を入力し、アプリのニックネームを適当に入力する。 アプリを追加をクリックすると、google-service.jsonがダウンロードできるので、ダウンロードし、Android Studio から以下のようにフォルダを切って格納しておく。 またこのタイミングでAndroid側のFirebaseを使う設定と、flutterのパッケージの設定をしておきます。 Firebaseの指示に従って、以下をandroid/build.gradleに追加します。 android/build.gradle ・・・ buildscript { ext.kotlin_version = '1.3.50' repositories { google() // なければ追加する jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.5.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.google.gms:google-services:4.3.4' // なければ追加する } } allprojects { repositories { google() // なければ追加する jcenter() } } ・・・ 加えて、android/app/build.gradleにも以下を追加します。 android/app/build.gradle ・・・ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply plugin: 'com.google.gms.google-services' // 追加する ・・・ そして、Firestore/Authenticationを使う前提として、pubspec.yamlに以下を追加します。 ※バージョンは公式ページを参照してください。 pubspec.yaml dependencies: flutter: sdk: flutter firebase_core: ^0.4.5 firebase_analytics: ^5.0.16 firebase_auth: ^0.14.0+9 cloud_firestore: ^0.12.11 追加したらpub getを実行してください。(私はいつも何故か2回実行しないとうまくいきません。) 下図のようにpubspec.yamlを開くと、右上にPub getの文字があるのでそちらをクリックします。 現在のバージョンではflutterのfirebaseパッケージを組み込むと必ずエラーが発生しますので、以下の対処をしておきます。 minSdkVersionを16から21に変更しておく defaultConfigにmultiDexEnabled trueの行を追加する。 参考:アプリの圧縮、難読化、最適化 - Android Developpers (公式) app/build.gradle defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "tech.tokkuengineer.flutter_firebase_sample" minSdkVersion 21 targetSdkVersion 29 versionCode flutterVersionCode.toInteger() versionName flutterVersionName multiDexEnabled true } setting.gradleに以下を追加 参考:【flutter】firebase登録時にsetting.gradeでのエラー - Qiita android/setting.gradle def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() def plugins = new Properties() def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') if (pluginsFile.exists()) { pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } } plugins.each { name, path -> def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() include ":$name" project(":$name").projectDir = pluginDirectory } ここまで出来たら、エミュレータをAndroidのイメージに変えてDebug-Developmentでビルドできるか確認します。 Dockerでのfirebase環境の構築 に入る前に、Firebaseプロジェクトの設定を行っておきます。 Firebase プロジェクトの画面からFirestoreをクリック Cloud Firestoreの画面からデータベースの作成をクリック データベースの作成画面でモードを選択 ※本番環境モードで開始すると、セキュリティルールを適切に設定するまでFirestoreの書き込みが全て拒否されます。開発環境であれば、まずはテストモードで開始することをお勧めします。 Cloud Firestoreのロケーションを選択する。好みではありますが、asia-northeast1を選択しておけば良いかと思います。 Dockerを使った環境構築 ここからはVSCodeで作業していきます。 firebase/Dockerfile Dockerfileとdocker-compose.yamlファイルを作成し、以下のように記載します。 GitHubリポジトリに用意してあります。 firebase\firebase-cli\Dockerfile FROM node:latest # Define working directory WORKDIR /workdir # Firebase toolsのインストール RUN apt-get -y update && apt-get install -y sudo openjdk-11-jdk RUN npm install -g firebase-tools # Expose ports ENV HOST 0.0.0.0 EXPOSE 4000 EXPOSE 5000 EXPOSE 5001 EXPOSE 8080 EXPOSE 9005 docker-compose.yaml version: "3" services: firebase-cli-container: build: ./firebase-cli container_name: firecli-container volumes: - ../firebase:/workdir これらの準備が出来たら、cd firebaseでフォルダを移動し、docker-compose upコマンドでコンテナをビルドします。 PS C:\Users\XXXX\AndroidStudioProjects\flutter_firebase_sample\firebase> docker-compose up Building firebase-cli-container failed to get console mode for stdout: The handle is invalid. => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 32B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/node:latest 1.0s => [1/3] FROM docker.io/library/node:latest@sha256:096cbc2667f5d1507d59d 0.0s => CACHED [2/3] WORKDIR /workdir 0.0s => CACHED [3/3] RUN npm install -g firebase-tools 0.0s => exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:9e31128f3f52b134c129a9f91f13f5bb91c3c9cd482f3 0.0s => => naming to docker.io/library/firebase_firebase-cli-container 0.0s Successfully built a9f91f13fc9e311c31128f32fb1349c9cd482f3525bb9c15ecb15b874b35c88a WARNING: Image for service firebase-cli-container was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`. Creating firecli ... done Attaching to firecli firecli exited with code 0 成功したら、以下のコマンドでコンテナを起動します。 docker-compose run -p 4000:4000 -p 5000:5000 -p 5001:5001 -p 8080:8080 -p 9005:9005 firebase-cli-container /bin/bash 起動したら、コンテナ内に接続されているので、そのままfirebaseの初期設定をします。 まずはfirebaseにログインします。 > firebase login i Firebase optionally collects CLI usage and error reporting information to help improve our products. Data is collected in accordance with Google's privacy policy (https://policies.google.com/privacy) and is not used to identify you. ? Allow Firebase to collect CLI usage and error reporting information? (Y/n) そのままEnterを押すとURLが表示されるので、Ctrlを押しながらクリックして開きます。 アカウント選択の画面で、ログインするユーザをクリックします。 Firebase CLIからのアカウントアクセスのリクエスト画面が出るので、許可をクリックします。 以下のような画面が出たら成功です。 VSCodeに戻って(コンテナ内のコンソールに戻って)firebase initを実行します。 以下のような画面でFiresotre、Functions、Hosting、Emulatorsを選択します。 ※選択するにはスペースを押します。 後は基本的にデフォルトで進めます。 途中Firebaseプロジェクトを聞かれるので、先の手順で作成したプロジェクトのdev側を選択しておきます。 firebase initが完了したらfirebase.jsonを以下のように修正します。 firebase.json { "firestore": { "rules": "firestore.rules", "indexes": "firestore.indexes.json" }, "functions": { "predeploy": [ "npm --prefix \"$RESOURCE_DIR\" run lint", "npm --prefix \"$RESOURCE_DIR\" run build" ], "source": "functions" }, "hosting": { "public": "public", "ignore": [ "firebase.json", "**/.*", "**/node_modules/**" ] }, "emulators": { "functions": { "host":"0.0.0.0", "port": 5001 }, "firestore": { "host":"0.0.0.0", "port": 8080 }, "hosting": { "host":"0.0.0.0", "port": 5000 }, "ui": { "enabled": true, "host":"0.0.0.0", "port":4000 } } } ここまで出来たらエミュレータを起動してみます。 コンテナ上で以下のコマンドを実行します。 firebase emulators:start ブラウザでhttp://localhost:4000 にアクセスし、以下のような画面が表示されたら成功です。 Firebase Hostingの設定 Firebase Authenticationを使ってユーザー認証を行っていると、App Storeへの申請時にプライバシーポリシーが必要となります。 せっかくFirebaseを使っているので、プライバシーポリシーとついでにアプリのLPをFirebase Hostingで用意しましょう。 プライバシーポリシー、利用規約作成 ついでにLP作成 とはいえ、上記のDockerでの環境構築の手順で環境構築は済んでいます。 firebase/publicがドキュメントルートになりますので、ここにLPなりプライバシーポリシーなりを作成して、デプロイすればOKです。 実際のコンテンツ作成はこの記事では割愛しますが、デプロイは以下のコマンドを用いて可能です。 firebase deploy --only hosting また別のFirebaseプロジェクトにデプロイする場合は、 firebase projects:list でプロジェクトの一覧を表示したあと、表示されたProject IDを指定して以下のコマンドを実行するとプロジェクトを切り替える事ができます firebase use <Project ID> この後firebase deployコマンドでデプロイすればプロジェクトが切り替わった状態でデプロイされます。 Lintの追加 これも後から入れるよりも最初に入れた方が良いので、pedanticを導入します。 pubspec.yamlに以下を追加します。 pubspec.yaml dev_dependencies: pedantic: ^1.11.0 こちら(公式リポジトリ)にある最新のanalysis_options.yamlをコピーしてプロジェクトの直下に置いておきます。 本記事執筆時点では1.11が最新でした。 analysis_options.yaml もちろんお好みでカスタムてOKです。(私はいつもこの方法でコピーするだけにしてます。) Flutter SDKのバージョン固定 共同開発を行っていると、Flutter SDKのバージョンを固定したくなる場合があります。これもプロジェクトの初期の段階で導入を済ませてしまった方が良いです。 バージョン固定するためにfvmというパッケージを使います。 fvmを導入するために、FlutterにバンドルされているDartとは別にDartをインストールします。 公式のインストール方法 Windows 管理者権限でPowerShellを開き、Chocolatoryを以下のコマンドでインストールします Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) インストールされたらchoco -vでバージョンが表示されるか確認しておきましょう。 そのままdart-sdkをインストールします。 choco install dart-sdk choco upgrade dart-sdk インストールと同時にPATHも通っていると思いますが念のため以下のコマンドで確認します。 PS C:\WINDOWS\system32> dart --version Dart SDK version: 2.10.4 (stable) (Wed Nov 11 13:35:58 2020 +0100) on "windows_x64" インストール時のメッセージに従って一度PowerShellのプロンプトを再起動しておきます。 ※またPub Cacheの方のPATHが正常に通らないので、手動で該当のフォルダを開いた後、パスを手でコピーしてインストール時に追加された環境変数のPATHを上書いておきましょう。 MacOS Terminalを開いて以下のコマンドを実行します brew tap dart-lang/dart brew install dart また各shellに合わせてPATHを通しておきます。 インストール時のメッセージに従って.zshrcなどに追記してください。 MacでのPATHの通し方が分からない方はこちらのような記事を参考にしてください。 fvmの導入 WindowsならPowerShell、MacOSならTerminalを開いて以下のコマンドを実行します。 pub global activate fvm 次にプロジェクトのルートに行き、以下のコマンドを実行します stableとなっているところを好きなバージョンに変更してもかまいません fvm install stable fvm use <version> このようにすると、Windowsなら.fvmフォルダの下に以下のようなファイルが出来上がります。 fvm_config.json { "flutterSdkVersion": "2.0.4" } これをgitの管理下にして共有しておくことで、他の共同開発者は、fvmをインストールした後にプロジェクトルートで fvm install とだけ打てば指定したバージョンがインストールされます。 MacOSの場合、.fvmの下にfvm_config.jsonに加えてflutter_sdkというシンボリックリンクが作成されます。 これをAndroid StudioのPreferences -> Languages & Frameworks -> Flutter -> SDKに指定すれば、pub getやビルドする際に、このflutter sdkを使うようになります。 共同開発者にWindowsユーザーがいる場合はこのシンボリックリンクは.gitignoreに追加して共有しないようにしておきます。(Windowsマシンでプロジェクトを開けなくなります) Windowsの場合は、シンボリックリンクが作成されないので、以下のような手順で手動でSDKを変更します。 C:\Users\XXXX\fvm\versionsの下に、インストールされたバージョン名のフォルダがありますのでコピーしてAndroid StudioのPreferences -> Languages & Frameworks -> Flutter -> SDKに指定します。 Android StudioのPreferences -> Languages & Frameworks -> Dartを開き、C:\Users\XXXX\fvm\versions\<指定したバージョン>\bin\cache\dart-sdkを指定し「OK」を押します。 これで、WindowsでもfvmのFlutter SDKを見に行くようになります。 まとめ 長々と手順化しましたが、これらはプロジェクトを作成して初期のタイミングで行った方が良いかと思います。 下手したらこれだけで1日潰れそうですね・・・ 参考 Flutter アプリに Firebase を追加する(公式) 環境設定 - KosukeSaigusa/recipe-app 開発者ごとでなく、プロジェクトごとにFlutterのバージョンを管理する fvmを使ってFlutter SDKのバージョンを切り替える - Qiita [BUG] Can't load Kernel binary: Invalid kernel binary format version. アプリの圧縮、難読化、最適化 - Android Developpers (公式) docker でfirebaseを試したメモ - Qiita Docker入門(第六回)〜Docker Compose〜 Docker compose ことはじめハンズオン - Qiita Firebase CLI の設定 - KosukeSaigusa/recipe-app
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Android最新リリースをFirebase App Distributionにアップロードしようとすると、`Downgrade to this release` となる

状況 これまでのリリース 1. 0.2.9(1) 2. 0.2.9(2) 3. 0.2.9(3) 4. 0.2.9(4) 行いたいリリースバージョン -> 0.3.0(1) Issue FADに 0.3.0(1) をアップロードした時、 Download ボタンではなく、 Downgrade to this release というボタンが表示される。 そして、このDowngrade を行ってしまうと、ログイン情報などが消えてしまうという状況が発生した。 解決法 Build number (ex.(1)) は、リセットしてはいけないみたい。 リリースbuildを、 0.3.0(5) にすると解決。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WebエンジニアがパパっとCordova + ガワネイティブでスマホアプリを構築する

タイトルの通り ガワネイティブとはスマホアプリに近いUIの外部サイトをネイティブアプリ上のwebviewにて画面いっぱいに表示してアプリ化することでWebサイトをアプリストアに載せられるようにする技術のことを指します。 今回は正確にはネイティブアプリではなくjsやhtmlでハイブリッドアプリを構築するフレームワークであるCordovaを使うのでガワネイティブの正確な定義に当てはまるかは微妙ですが、まあ便宜的にガワネイティブという言葉を使います。 ちなみにPWAというブラウザから直接ホーム画面にWebサイトを登録してもらいアプリのように扱えるようになるPWAという技術はありますが一般的にはまだまだ知名度が低く、やはりアプリストアに載せることができるのは集客上結構なアドバンテージとなりそうです。 あとはWebエンジニアが1からスマホアプリ開発を習得するのは大変なのでまあなんとか楽したいという思想。 今回はAndroid+Windows10で開発行いました。 導入手順は下記URLなどを参考にしてます。 https://qiita.com/danishi/items/c7656d45bde73bf62feb 今回はとりあえずCordovaのwebviewで外部サイトを表示し、 その中でネイティブアプリのAPIで取得した情報などを外部サイトと双方向でデータ通信する方法を記述します。 スマホアプリ開発は今日始めて勉強したレベルなので間違ってるところはあるかもしれません。 iOSは持ってないのでまだ試してないですが多分大きくは変わらないと思います。 Cordova側 コマンドプロンプトでプロジェクトディレクトリに入りとりあえずInAppBrowserというプラグインを追加します。 これはCordova上でwebviewを表示するためのプラグインとなります。 cordova plugin add cordova-plugin-inappbrowser Cordovaで記述するソース index.js document.addEventListener('deviceready', onDeviceReady, false); function onDeviceReady() { function openInAppBrowser() { // ネイティブの機能を使いたい場合は_selfではなく_blankであることが必須 var target = "_blank"; // フルスクリーン指定することでアドレスバーとかを表示させなくする var options = "location=no,fullscreen=yes"; // 外部サイトを開く var inAppBrowserRef = cordova.InAppBrowser.open('_外部サイトのURL_', target, options); inAppBrowserRef.addEventListener('message', messageCallBack); // target="_blank"のタブが閉じたら同時にアプリを終了させる inAppBrowserRef.addEventListener('exit', function () { navigator.app.exitApp(); }); // 親画面から外部サイト上で特定のスクリプトを実行する 今回は単純に10秒後にアラートを出す setTimeout(function (){ inAppBrowserRef.executeScript({code: 'alert("test");'}) }, 10000); } // 外部サイトのイベントで受け取ったデータを処理する function messageCallBack(data){ alert(data.value); } openInAppBrowser(); } inAppBrowserRef.executeScript にて例えばネイティブの機能で取得したデバイス情報などをコードに埋め込み実行させることで外部サイトにデータを送ることができる感じですね。 外部サイト側 app.js // Cordova側に外部サイト上のデータを送信する function postMessage() { var messageObj = { "value": 'hogehoge', }; var stringifiedMessageObj = JSON.stringify(messageObj); webkit.messageHandlers.cordova_iab.postMessage(stringifiedMessageObj); } postMessage(); たったこれだけでデバイス、外部サイトの双方向のデータの受け渡しができるようです。 外部サイトのJSから直接Cordovaのプラグイン機能を呼び出すことは無理ですが、このようにデータを経由しあえばどうにでも行けそうです。 ちなみに親タブがあって、その親タブとtarget="_blank"で開いた外部サイトタブがデータを双方向に通信しあってるイメージで、target="_self"にした場合は親タブそのもののURLが切り替わるようで上記の方法は使えなくなります。 外部サイト側だけで機能が完結していてネイティブの機能連携など一切必要ない場合はtarget="_self"でもできそうですがこの場合マジでコードが2行とかで完結しそうなのでこんなんで審査通るのか疑問です。。。 あ、あとクッキー、ローカルストレージの保存とかはこの段階だとまだ課題としてありそうですね。 メリット・デメリットとか所管 メリットとしてはレスポンシブでうまく実装すればPC(Web)、iOSとAndroidアプリ、タブレットなどマルチデバイス対応を本当に最小工数で完結させることができそうです。 大きな工数がとれない個人開発などにおいてはかなり有用なテクニックになりそうです。 Webエンジニアがスマホアプリの開発を初めて行うというような際の学習コストも普通にハイブリッドアプリを構築するよりも小さく済みそうです。 デメリットとしてはやはり審査ですね。 ガワネイティブ自体はよく使われる技術ですが、本当にWebサイトをそのまま表示するだけのようなアプリは審査に落ちることも多々あるらしいです。 あと何気に致命的だと思ったのはネイティブ/外部サイト間でデータの受け渡しができるとは言っても 例えばAdMob(Googleが提供するアプリ向けの高単価広告サービス)など用のplugin導入には障壁があって(っていうか普通に導入無理じゃね?)、もしかすると広告収入モデルで収益化を目指してる場合はあまり向いてない可能性はありそうです。 こういうところまで考慮するなら固定オーバレイ広告を載せる前提でFlutterやガワネイティブという文字通りネイティブアプリとして開発した方が自由度は上がりそうです。 簡単そうで面倒なガワネイティブ、今だとどう実装するのが一番なんですかねぇ。。。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Huaweiスマホのbloatwareを無効化するbatファイル[adb]

はじめに Huaweiのスマホを買ったのですが、bloatware(あらかじめインストールされている余計なアプリ)があまりにも多かったので、バッチで無効化したいと考えました。 対象はYahoo、Softbank、Huawei、Google、その他のアプリです。比率としては$1:1:4:4:0.5$くらいでした。 ADBで無効化したいアプリを順番に無効化するスクリプトをインターネット上の情報をもとに自分用にアレンジしました。無効化すると、設定などの重要なアプリが動かなくなるので、アプリの選択には試行錯誤しました。 環境 Windows 10 adbを導入済み P20 Liteのドライバをインストール済み Huawei P20 Lite YMobile ver Developer optionを有効化済み USBデバッグを有効化済み 無効化スクリプト Windowsのバッチファイルになります。adbがC:\adbにある設定になっていますので、各自の環境に合わせて調整してください。 エミュレーターが復活することがあるので、パッケージをインストールするたびにエミュレーターを削除しています。また、無効化の間に100msの遅延を設けています。 @echo off set /p Y=C:\adb cd %Y% adb devices pause for %%X in ( "jp.softbank.mb.dmb" "jp.co.yahoo.android.ymobile.mail" "jp.softbank.mb.cbrl" "jp.co.yahoo.android.yjtop" "jp.softbank.mb.parentalcontrols" "jp.co.yahoo.android.ymsetupman" "com.hicloud.android.clone" "com.huawei.camera" "com.huawei.systemmanager" "com.huawei.android.thememanager" "com.huawei.android.chr" "com.huawei.android.FloatTasks" "com.huawei.android.hsf" "com.huawei.android.mirrorshare" "com.huawei.search" "com.huawei.contactscamcard" "com.huawei.fido.uafclient" "com.huawei.gameassistant" "com.huawei.hidisk" "com.huawei.himovie.overseas" "com.huawei.hitouch" "com.huawei.iaware" "com.huawei.parentcontrol" "com.huawei.pcassistant" "com.huawei.vassistant" "com.huawei.videoeditor" "com.android.calendar" "com.android.contacts" "com.android.carrierconfig" "com.android.cellbroadcastreceiver" "com.android.deskclock" "com.android.gallery3d" "com.android.htmlviewer" "com.android.hwmirror" "com.android.mediacenter" "com.android.printspooler" "com.android.vpndialogs" "com.android.wallpaper.livepicker" "com.android.wallpapercropper" "com.example.android.notepad" "com.google.android.music" "com.google.android.apps.docs" "com.google.android.apps.photos" "com.google.android.apps.tachyon" "com.google.android.feedback" "com.google.android.googlequicksearchbox" "com.google.android.gm" "com.google.android.videos" "com.google.android.youtube" ) do ( powershell -nop -c "& {sleep -m 100}" adb emu kill adb shell pm uninstall %%X adb emu kill adb shell pm uninstall -k --user 0 %%X ) pause 無効化したいアプリの名前がわからない App inspectorというアプリを用いることでアプリの名前(com.huawei.hitouchなど)の特定が可能です アプリを復活させるには 必要なアプリも無効化してしまった場合には下のコマンドで復活させることができます adb shell cmd package install-existing <name of package> 無効化したアプリを有効化するスクリプト 上で述べたスクリプトで無効化したアプリは以下のスクリプトを用いることですべて有効化できます。 @echo off set /p Y=C:\adb cd %Y% adb devices pause for %%X in ( "jp.softbank.mb.dmb" "jp.co.yahoo.android.ymobile.mail" "jp.softbank.mb.cbrl" "jp.co.yahoo.android.yjtop" "jp.softbank.mb.parentalcontrols" "jp.co.yahoo.android.ymsetupman" "com.hicloud.android.clone" "com.huawei.camera" "com.huawei.systemmanager" "com.huawei.android.thememanager" "com.huawei.android.chr" "com.huawei.android.FloatTasks" "com.huawei.android.hsf" "com.huawei.android.mirrorshare" "com.huawei.search" "com.huawei.contactscamcard" "com.huawei.fido.uafclient" "com.huawei.gameassistant" "com.huawei.hidisk" "com.huawei.himovie.overseas" "com.huawei.hitouch" "com.huawei.iaware" "com.huawei.parentcontrol" "com.huawei.pcassistant" "com.huawei.vassistant" "com.huawei.videoeditor" "com.android.calendar" "com.android.contacts" "com.android.carrierconfig" "com.android.cellbroadcastreceiver" "com.android.deskclock" "com.android.gallery3d" "com.android.htmlviewer" "com.android.mediacenter" "com.android.printspooler" "com.android.vpndialogs" "com.android.wallpaper.livepicker" "com.android.wallpapercropper" "com.example.android.notepad" "com.google.android.music" "com.google.android.apps.docs" "com.google.android.apps.photos" "com.google.android.apps.tachyon" "com.google.android.feedback" "com.google.android.googlequicksearchbox" "com.google.android.gm" "com.google.android.videos" "com.google.android.youtube" ) do ( powershell -nop -c "& {sleep -m 100}" adb emu kill adb shell cmd package install-existing %%X ) pause コメント 以下に述べるアプリを消すと設定が開かなくなったり、上スワイプでのアプリ終了ができなくなります。 com.android.managedprovisioning com.android.providers.userdictionary 無効化、有効化に失敗した場合はもう一度スクリプトを実行すると成功することがあります。 参考リンク Huaweiデバイスのbloatwareリスト bloatwareの無効化方法
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

アプリのセーブデータを引き継ぐ

(完全に自分用メモです) TL;DR 大体のゲームのセーブデータは adb backup / adb restore で引き継げます ただちょっと怖い方法でもある(ような気がします) 確認したアプリ(現時点ではゲームしかないです) Phigros DanceRail3 必要なもの 古い端末 新しい端末 PC(adbが動けば何でもいい、何なら実機でもいい) 具体的な手順 古い端末とPCを接続する PC側でadb backup <該当するアプリのパッケージ名> -f <適当なファイル名>を実行する PCに接続されている端末を新しい端末に付け替える PC側でadb restore <適当なファイル名> を実行する 仕組みは古い端末のバックアップを新しい端末にリストアするだけです おわり 短いけどこれで終わります ありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む