20220125のAndroidに関する記事は4件です。

【Android】バックグラウンド処理をServiceからWorkManagerに移行してみた

はじめに 皆さん、ごきげんよう!れぶです! 今回の記事は、バックグラウンド処理の実装についてです。 Android 8.0(Oreo)以降、バックグラウンド処理に対する厳しめな制限が導入されました。その結果、Service(特にバックグラウンドサービス)を使った実装をすると、動作が安定しません。詳しくは、こちらを参考にしてみてください。 なので、バックグラウンド処理を行う際には、Android Jetpack系のWorkManagerを使うことをGoogleは推奨しています。このWorkManagerは、電池寿命の向上・互換性の高さ・様々な条件や制約を付与できるなど、メリットが沢山あります。API level 14から機能します。 そのような背景から、今回はServiceとWorkManagerを比較しながら、ボタンを押すと15分ごとにバックグラウンド処理を定期実行する実装方法を書いていきます。それでは参りましょう!! この記事の対象者 今までServiceを使ってバックグラウンド処理をしていたけど、WorkManagerを使った実装に移行したい方 開発環境 Mac Android Studio 4.1.2 Java 8 compileSdkVersion 31 minSdkVersion 16 Serviceを使った実装 コードの主要部分がこちらになります。 Serviceを継承したクラスの中でTimerを使うことで、定期的なバックグラウンド処理を実現しています。 MainService.java private Timer timer; @Override public int onStartCommand(Intent intent, int flags, int startId) { if (timer != null) { timer.cancel(); timer = null; } //15分ごとに定期実行 timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { //バックグラウンド処理 } },0,900000); return START_NOT_STICKY; } ボタンが選択されると、それぞれIntentでServiceの起動・停止を行います(フラグメント内)。 MainFragment.java @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); Button bt_start = view.findViewById(R.id.bt_start); Button bt_stop = view.findViewById(R.id.bt_stop); //startボタン選択時 bt_start.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //サービス起動 Intent intent = new Intent(getActivity(),MainService.class); getActivity().startService(intent); } }); //stopボタン選択時 bt_stop.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //サービス停止 Intent intent = new Intent(getActivity(),MainService.class); getActivity().stopService(intent); } }); } WorkManagerを使った実装 登場人物 以下の3つのオブジェクトが中心です。 オブジェクト 説明 Worker バックグラウンド処理を定義 WorkRequest 処理の実行条件やタイミングを記録。一度だけ処理を実行するOneTimeWorkRequestと定期的に処理を実行するPeriodicWorkRequest(今回はこっち)がある。 WorkManager Workの実行状況を監視 実装の流れ ❶ build.gradleファイルに依存関係を追加 build.gradle dependencies { implementation "androidx.work:work-runtime:2.7.1" } 現時点では、WorkManagerのバージョンは2.7.1です。適宜変更してください。 ❷ バックグラウンド処理を定義 MainWorker.java public class MainWorker extends Worker { public MainWorker( @NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); } @Override public Result doWork() { //バックグラウンド処理 return Result.success(); } } Workerを継承したクラスのdoWorkメソッド内に、バックグラウンド処理を書きます。Serviceを継承したクラスのonStartCommandメソッド内に書いていた内容が、まさにこの部分に該当します。 ❸ WorkRequestを作成 ❹ WorkManagerに❸を追加or削除 MainFragment.java         @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); Button bt_start = view.findViewById(R.id.bt_start); Button bt_stop = view.findViewById(R.id.bt_stop); //startボタン選択時 bt_start.setOnClickListener(new View.OnClickListener() { @RequiresApi(api = Build.VERSION_CODES.O) @Override public void onClick(View v) { //15分おきに定期実行を開始 //Wi-Fiに繋がっている、かつ電池残量低下モードになっていない場合のみ Constraints constraints = new Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) .setRequiresBatteryNotLow(true) .build(); PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder( MainWorker.class, Duration.ofMinutes(15) ) .setConstraints(constraints) .addTag("タグ名") .build(); WorkManager.getInstance(getActivity()).enqueue(workRequest); } }); //stopボタン選択時 bt_stop.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //定期実行をキャンセル WorkManager.getInstance(getActivity()).cancelAllWorkByTag("タグ名"); } }); } IntentでServiceの起動・停止を行なっていた箇所がここに該当します。startボタンで定期実行を開始し、stopボタンで停止しています(フラグメント内)。 PeriodicWorkRequestを作成する際にタグを追加しているのは、どの定期実行をキャンセルするかを識別するためです。 WorkManagerはServiceと違い、様々な条件や制約を付与することができます。今回のWorkManagerのコードでは、ConstraintsオブジェクトをWorkRequestに登録し、Wi-Fiとバッテリーモードの状態による制限を加えています。 備考 今回のサンプルはあくまで一例です。他にも、 定期実行の間隔の変更(最小時間は15分) 一回のみの処理実行 Workerへのデータの受け渡し 充電や端末の状態などによる制約の付与 などなど、沢山の条件を設定することが可能です。 詳しくは、公式ドキュメントやこちらの記事を参考にしてみてください。自身も非常に参考にさせて頂きました。 WorkManagerの使い所 公式ドキュメントで以下のように述べられています。これが基本原則です。 WorkManagerは、ユーザーが画面から移動した場合、アプリが終了した場合、デバイスが再起動された場合でも、確実に実行する必要がある処理を対象としています。次に例を示します。 ログやアナリティクスをバックエンドサービスに送信する アプリデータをサーバーと定期的に同期する 何がなんでも裏で動作させたい処理にWorkManagerを使うことが推奨されています。 他にも、データのレポーティングや画像の保存、ツイートなどが挙げられます。 逆に非推奨な処理を以下にまとめました。 処理 代替策 ユーザーが画面を離れた時に、即時実行したタスクが終了する可能性がある処理 Kotlin Coroutine(Javaの場合は、Executorなど) アラームやカレンダーなど、正確な時間どおりに実行する必要がある処理 AlarmManager ※ メディア再生にはForegroundServiceを使うことが推奨されていましたが、Android 12以降、ForegroundServiceの制限ができました。その代替策として、WorkManagerが挙げられていました。詳しくは、この記事をご覧ください。 おわりに 今回は、バックグラウンド処理をServiceからWorkManagerに変えて実装する方法を中心にまとめていきました。 基本は4ステップで出来るので、意外と簡単かなと思います。条件や制約次第で、多様なパターンのバックグラウンド処理の仕方があるので、各々試してみてください。その際には是非、適切な場面でWorkManagerを使えているかを意識してみてください! なお、今回自身がこの記事を書くにあたり、ボタンを押すとバックグラウンド状態で通知が15分ごとに届くサンプルプログラムを作成しました。その際に書いたコードを以下のGitHubに載っけているので、参考の一つにしてみてください。 https://github.com/seiyaleb/BackGroundTrialApp 参考書籍・参考サイト 基礎&応用力をしっかり育成! Androidアプリ開発の教科書 なんちゃって開発者にならないための実践ハンズオン(書籍) WorkManagerでタスクのスケジュールを設定する(公式ドキュメント) WorkManagerの概要(公式ドキュメント) WorkRequestの定義(公式ドキュメント) バックグラウンド処理ガイド(公式ドキュメント) いまさらWorkManager〜概要編〜 [Android]Workでバックグラウンド処理を定期実行する WorkManagerの内部を見てみた WorkManager
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FlutterでFirebaseを使ってみる〜Firebase導入編(Android)〜

投稿の経緯 FlutterのキャッチアップでFirebaseと連携してFirestoreを使うサンプルプロジェクトを立ち上げました。今回はAndroidアプリにFirebaseを導入してエミュレーターでビルドするところまでを書こうと思います。 iOSアプリにFirebaseを導入する記事は↓コチラ↓ 環境 Flutter:2.8.1 MacOS:12.1 サンプルプロジェクト GitHubにコードPushしています。気になる方はご覧ください。 Firebaseの導入 公式情報を参考にして進めていきます。 Firebaseプロジェクトの作成はiOSの記事の方で作成したのでアプリをFirebaseに登録するところから書いていきます。 アプリをFirebaseに登録する Firebaseプロジェクトを作成したらコンソールのAndroidアイコンからアプリをFirebaseに登録しましょう。 Android パッケージ名の箇所にアプリのパッケージ名を入力します。 パッケージ名は、アプリケーション ID と呼ばれることもあります。 パッケージ名は/Flutterプロジェクト/android/app/build.gradle/から取得します。 build.gradle defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.ken.firestore_training" // 以下省略 // } 今回のサンプルプロジェクトの場合はcom.ken.firestore_trainingになります。 アプリのニックネームとデバッグ用の署名証明書 SHA-1は任意なので今回はスキップしてアプリを登録します。 Firebase 構成ファイルを追加する 続いてgoogle-services.jsonをダウンロードしてファイルをFlutterアプリに追加します。 保存場所は/Flutterプロジェクト/android/app/に保存します。 続いて、Gradleファイルにgoogle-servicesプラグインを追加します。 /Flutterプロジェクト/android/build.gradleに、GoogleサービスのGradleプラグインを含めるためのルールを追加します。GoogleのMavenリポジトリがあることも確認してください。 build.gradle buildscript { ext.kotlin_version = '1.3.50' repositories { google() // Google's Maven repository ここがあるか確認 mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:4.1.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.google.gms:google-services:4.3.10' // Google Services plugin を追加 } } allprojects { repositories { google() // Google's Maven repository ここがあるか確認 mavenCentral() } } rootProject.buildDir = '../build' subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" } subprojects { project.evaluationDependsOn(':app') } task clean(type: Delete) { delete rootProject.buildDir } 続いて、/Flutterプロジェクト/android/app/build.gradle/で、GoogleサービスのGradleプラグインを適用します。 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' // Google Services plugin を追加 // 省略 ここまでできたらターミナルでflutter packages getを実行してください。 FlutterFireプラグインを追加する コチラの記事にFlutterFireプラグインを追加する内容を記事にしています。 アプリをビルドする FlutterFireプラグインを追加してプラグインをメジャーバージョンへアップデートしたらビルドを実行しましょう。 The plugin cloud_firestore requires a higher Android SDK version. Fix this issue by adding the following to the file /Users/ユーザー名/Library/Mobile Documents/com~apple~CloudDocs/Flutter_projects/アプリ名/android/app/build.gradle: android { defaultConfig { minSdkVersion 19 } } Note that your app won't be available to users running Android SDKs below 19. Alternatively, try to find a version of this plugin that supports these lower versions of the Android SDK. するとこのようなエラーが発生すると思います。このエラーは下記のstackoverflowの記事で解説されています。 私はひとまずminSdkVersion 30に変更して対応しました。 この状態でビルドすれば成功すると思います。 おわりに 今回はFlutterプロジェクトのAndroidアプリにFirebaseを導入して、エミュレーターでビルドするところまでを記事にしました。 ご覧いただきありがとうございました。 こうしたほうがいいや、ここはちょっと違うなど気になる箇所があった場合、ご教示いただけると幸いです。 お知らせ 現在副業でiOSアプリ開発案件を募集しています。 ↓活動リンクはこちら↓ https://linktr.ee/sasaki.ken Twitter DMでご依頼お待ちしております!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Flutter] ビルド時のエラーの解決策 ( No matching client found for package name)

flutterで、androidのビルド時に下記エラーがでて、詰まったので共有です。 エラー文 Execution failed for task ':app:processDebugGoogleServices'. > No matching client found for package name 'com.xx.xx' 解決策 google-services.jsonのpackage_nameとbuild.gradleのapplicationIdの2つを一致させる必要がありました。 android/app/google-services.json "client": [ { "client_info": { "mobilesdk_app_id": "xxxxxxxxxxx", "android_client_info": { "package_name": "com.xx.xx" //ここ } }, android/app/build.gradle defaultConfig { applicationId "com.xx.xx" //ここ minSdkVersion 16 targetSdkVersion 28 versionCode 1 versionName "1.2.2" multiDexEnabled true } 参考 最後に 私は現在、株式会社ダイアログという物流×ITの会社に勤務しております。 現在、エンジニアを募集していて、カジュアル面談も実施しているのでお気軽にご連絡ください!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

vdexファイルのデコンパイル

カスタムアンドロイドにてよくわからないAPIを調べるとき用。 要するに以下に無い場合は端末内にあるはず。という前提で https://cs.android.com/ あらかじめstringsとgrepで当たりをつけておくと楽 流れ vdex -> cdex -> dex -> jar(classファイル) -> jar(javaファイル) -> jar解凍 vdex -> cdex vdexExtractorを使う。 https://github.com/anestisb/vdexExtractor READMEにはdependencyとかdisassembleとか書いてあるけど とりあえずiとoを指定してやればcdexファイルが出来る ヘルプに出てくる=(イコール)は不要 cdex -> dex cdexはcompact dexとか言うらしい。 https://github.com/anestisb/vdexExtractor/issues/23 の compact_dex_converter_linux.zip を落として解凍すればそのまま使える。 windowsからだとそれっぽいのが添付されているので それで行けるんじゃないかな?(未確認) なんとか.cdex.new というファイルが作成されるので .dexにリネームする。 dex -> jar ここからは誰か書いてると思うけどdex2jarで 注意点としてはすでにあるもの叩いてもうまく動かず、 usageにある通りに自分でビルドしたものでないとダメっぽい。 jar(.class) -> jar(.java) ようやくjavaファイルが出てくる fernflowerを使う https://github.com/JetBrains/intellij-community の plugins/java-decompiler/engine/ が対象 以下に細かい手順書いてくれてる人がいます。m(__)m https://troushoo.blog.fc2.com/blog-entry-372.html jarが巨大ファイルだと重くて進まない可能性があるので 先に解凍してからclassファイルを個別にやった方が良い場合もある。 解凍 unzip なり jarなりで普通に解凍するだけ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む