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

[Flutter] FCM vs Local Notification

はじめに FlutterでAndroidとiOSのアプリを両方開発しているところで、Push Notificationを実装することになりました。 最初はFCMとLocal Notificationの機能に関して紛らわしいことがありましたので、今回はこれに関して整理しようと思います。 FCM (Firebase Cloud Messaging) Firebase Cloud Messaging(FCM)は、メッセージを無料で確実に送信するためのクロスプラットフォーム メッセージング ソリューションです。 Firebaseサイトで定義されてる概念で、Firebaseサーバーを使って簡単にユーザーにメッセージを送信することができるとで理解すれば、大丈夫だと思います。 FlutterにFCMを適用する方法 Flutterでは、firebase_messagingのパッケージを追加して使用することができます。 注意することはiOSはAPNsキーもしくはAPNs認証書を登録を事前にしなければ、送信できないので、面倒だけどXcodeの方でAPNsの登録を含めてbundle ID設定やProvisioning Profile設定をしましょう。 あと、他のFirebaseパッケージ、例えば、firebase_authやfirebase_coreなどを使うことになったら、バージョンの互換性も考えないとビルドエラーが起こる可能性もあるので気をつけた方がいいです。 FlutterのLocal Notification A cross platform plugin for displaying and scheduling local notifications for Flutter applications with the ability to customise for each platform. これもFCMみたいにメッセージを送信するためのクロスプラットフォームです。 FlutterにLocal Notificationを適用する方法 Local Notificationもfirebase_messagingようにflutter_local_notificationsのパッケージを追加すれば使用することができます。 FCMとLocal Notificationの共通点 両方Android,iOSにメッセージを無料で送信することができる メッセージの予約可能 Notification許可ダイアログを出すことができる (これ以上何かあったら、Feedbackしてください?) FCMとLocal Notificationの相違点 FCMはiOSの方の追加的な対応が必要(bundle ID, Provisioning Profile, APNsキー, tokenなど) FCMはメッセージの中に画像を表示したいなら、Flutter上にObjective-Cで対応しなければならない。 FCMはfirebaseをデータベースとして使用している場合は、クラウド機能を使用してデータベースに加えられた変更をlistenすることができる。 用語の違い:機能がほぼ同じでFCMとLocal Notificationを話すとき、プッシュ通知もしくはPush Notificationと言われるですが、これは正しくないです。 Local Notificationはデバイス上にローカルにアプリ自体から送信、予約されたNotificationです。 Push NotificationはiOSやAndroidのクラウドシステム(APNs,FCMなど)を通じてアプリに送信されたNotificationです。 まとめ つまり、用語的にFCMはPush Notification, ローカルで送信する通知はLocal Notificationです。FCMはユーザーのデータベースをもとにAPNsとトークンを通してメッセージを送信、Local Notificationはこれに関係なくてメッセージを送信することができます。もちろん、Push Notificationの方がLocal Notificationより細かい設定や実装が必要です。実装したいことによって、ちゃんと検討して実装した方がいいと思いますね。 参考 いつもFeedback歓迎 Feedbackはコメントでお願いします。 では、Happy coding!??
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

TargetSDK 30対応中にハマったこと

はじめに CYBIRDエンジニア Advent Calendar 4日目担当の@chikako_ikedaです。 3日目は@kyorokyoroのアプリの通信回数を減らすためにやったことでした。 最近は速い通信規格が出てきてあまり気にならないこともありますが、アプリの通信回数はアプリの操作感が変わるので、「回数を減らす」というのは大事ですよね。 概要 2021/11/01からGoogle PlayではTargetSDKをAPI Level 30(Android11)へ対応することが必須となりました。 CYBIRDのアプリでも順次対応を進めているところですが、こんなところでハマったよ、ということで、 APKの署名スキーマv2への対応について紹介しようかと思います。 ※以下、「TargetSDKをAPI Level 30(Android11)へ対応」は「TargetSDK30対応」と記載します。 目次 発端:出来上がったAPKがインストールできない 調査:とりあえず、エラー内容を確認しよう 原因:TargetSDK30から署名スキーマv2への対応が必須に 解決:署名スキーマv2の署名を追加しよう APKの署名スキーマv2への対応 発端:出来上がったAPKがインストールできない 当社のアプリは全てではないですが、Jenkinsを使ってビルドの自動化を行なっています。 各開発者の環境に左右されず、ビルド後に必要な処理を自動でやることが可能になります。 (例:テスト用バイナリを特定のサーバにバックアップする、とか) コードを修正して、Jenkinsでのビルドが成功したのち、実機で確認すべくインストールをしようとしました。 ところが、「このアプリはインストールできません」とだけ表示を出し、インストールに失敗しました。 ビルドログを見ても、「Success」と出ている。 色々バージョンを別に確認をしたところ、TargetSDK30対応分のコードでだけ発生していました。 調査:とりあえず、エラー内容を確認しよう 古のアンドロイダーである自覚のある私は、こういう時に真っ先にケーブルを繋ぎADBコマンドを叩きます。 ※ADBはAndroidの開発ツールです。  端末の中に入ったり、アプリ内DBの中身を引っこ抜いたりするのに使います。 // -r オプションをつけると上書きインストールになります adb install -r ${APKのパス} adb: failed to open ${APKのパス}: Operation not permitted 許可がない。しかも、「署名が違うから入れられない」というありがちなエラーではない。 署名をしたけれど不正で、どうやら端末には入れられない、とのこと。 この現象に気づいたのが間の悪いことに、テスト開始前夜。 当社のテストは原則として、製品版相当の状態で確認を行うため、テスト担当の方に慌てて一時的にデバッグ版での確認をお願いすることとなりました… 原因:TargetSDK30から署名スキーマv2への対応が必須に ところで、TargetSDK30対応を始める前に事前調査を行っていました。2021年の3月くらいに。 その中に、「署名スキーマv2が必須になる」という記載があったことを思い出しました。 APK署名スキームv2が必要(下位互換でv1も必要) ちなみに、署名スキーマv2って何? という話なのですが、ものすごく大雑把に言うと、 いままでのアプリに付与していた開発者(あるいは配信者)の本人確認にプラスした情報が必要になるよということです。 詳細はこちら。 この署名スキーマv2は、API Level 24(Android 7.0)から対応していたそうです。 ただし、この問題が起きるのはAndroidStudioでAPKを作っていない場合です。 AndroidStudioを使っている場合は、minSdkVersionを見て、自動でこの署名の切り替えをしてくれているそうです。 だからbuild Valiantをreleaseにして実行していた時は、普通に実機で動いたのか… 解決:署名スキーマv2の署名を追加しよう 既存のJenkinsのジョブ設定にあるビルドと署名では実機インストールができないので、 対応しなくてはいけません。 ただ、幸運なことにいままで使っていたkeystore (署名のためのファイル)はそのまま使えます。 ちなみに、問題が起きたアプリの下限OSはAPI Level 23(Android 6.0)なので、署名スキーマv1の署名も必要です。 なので、方針としては以下の通りになります。 いままで通りのビルド+署名を行う 署名スキーマv2を追加して署名する Jenkinsのビルドシェルに、以下のコマンドを追加しました。 ./apksigner sign -ks ${keystoreのパス} --ks-key-alias ${アプリのエイリアス} --v1-signing-enabled=true --v2-signing-enabled=true ${APKのパス} でも、こんなコマンド1つで本当に、署名できてるの? と不安になるかと思います。 なので、検証もしてみましょう。 apksigner verify --print-certs -v [署名済みのAPKファイル] このコマンドを叩くと、以下のような形で検証結果が出てきます。 v1スキーマとv2スキーマ両方がtrueになっていれば、対応成功です。 Verifies Verified using v1 scheme (JAR signing): true Verified using v2 scheme (APK Signature Scheme v2): true ※以下略 なお、この署名方法はTargetSDK30対応をしていなくても、特に問題なくインストールできることも確認しました。 さいごに 実装とか設定にばかり目が行きがちになりますが、ツールへの対応も忘れちゃいけませんね。。。 明日のCYBIRDエンジニア Advent Calendar 2021 5日目は、 @kappysan が担当します。 ありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Navigation SDK v2 for Androidを試してみる (インストール編)

はじめに いよいよ、待ちに待ったMapbox Navigation SDK v2がリリースされました!そこで、ここでは公式サイトの手順にしたがってまずはAndroidのナビゲーションアプリを動かしてみたいと思います。 v1との違い v2はMaps SDK v10をベースにナビゲーション機能を提供します。それに伴い、カメラ周りの実装などが大きく変更されました。特にAndroidはUI周りの変更が顕著です。 例えば、v1ではViewを継承したNavigationViewが実装されていました。これを使うことで、全部入りのナビゲーションはこのサンプルのように少ない記述量で作成することができました。これに対し、v2ではNavigationViewが提供されません。代わりに、ナビゲーションのための各パーツが提供されており、自身でそれらを組み合わせて使います。v1におけるこのサンプルがイメージとしては近いです。 また、Navigation Core (MapboxNavigation等)はv1のコードをベースに開発されたため、v1の面影があります。それに対し、UIの実装は新規に行われてたため、完全な別物となっています。 そのため、公式ドキュメントで紹介されているサンプルも"To simulate your first navigation experience using our UI components"という割にはコード量が多いです。ただ、基本的にはコピペで動くので、今回はまず動かすことに主眼を置きたいと思います。 注意事項 この記事では2021/11/25現在で最新のv2.0.2を使用します。 Pricingにご注意ください。特にMAUは100まで無料ですが、ここに記載されているようにアプリケーションの削除・インストールでカウントアップします。デバッグ中に何度も削除・インストールを繰り返すと無料枠を超える可能性があります。 インストール Mapbox Navigation SDK for Android v2の公式ドキュメントはこちらです。Get started の中の Installation から始めます。 基本的には書いてあるとおりに進めればOKですが、以下の点に注意してください。 新規プロジェクト Minimum SDKはAPI21: Android 5.0 (Lollipop) 以上が必要です。Empty Activityで大丈夫です(使わないので)。 トークン MapboxのアクセストークンにはPublic, Secretの二種類が存在します。 Publicトークン: 地図の取得、ナビゲーション情報の取得等アプリケーションからMapboxのAPIを呼ぶ際に使用。pk.で始まる文字列 Secretトークン: アカウントの設定、SDKバイナリのダウンロードなど、開発時に使用。sk.で始まる文字列 そこで、まずNavigation SDKをダウンロードするためにアカウントサイトで「Downloads:Read」スコープの付与されたSecretトークンを作成します。そして、«USER_HOME»/.gradle/gradle.propertiesの中に以下を記載します。 ~/.gradle/gradle.properties MAPBOX_DOWNLOADS_TOKEN=PASTE_YOUR_SECRET_TOKEN_HERE これが後ほどビルドの際に使用されます。Androidのプロジェクトの中で直接指定することも可能ですが、間違えてGitHub等にPushしてしまう危険性があるので注意してください。 Mavenの設定 ドキュメントでは以下の設定をプロジェクトレベルのgradle.propertiesに書くように指示されています。 gradle.properties allprojects { repositories { maven { url 'https://api.mapbox.com/downloads/v2/releases/maven' authentication { basic(BasicAuthentication) } credentials { // Do not change the username below. // This should always be `mapbox` (not your username). username = "mapbox" // Use the secret token you stored in gradle.properties as the password password = project.properties['MAPBOX_DOWNLOADS_TOKEN'] ?: "" } } } } Android Studio Arctic Foxでプロジェクトを作成した場合、allprojectsが存在しません。そこで、プロジェクトレベルのsettings.gradleを開き、以下のように記載します。project.properties['MAPBOX_DOWNLOADS_TOKEN']がthis.properties['MAPBOX_DOWNLOADS_TOKEN']になっている点にご注意ください。 settings.gradle dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() jcenter() // Warning: this repository is going to shut down soon maven { url 'https://api.mapbox.com/downloads/v2/releases/maven' authentication { basic(BasicAuthentication) } credentials { // Do not change the username below. // This should always be `mapbox` (not your username). username = "mapbox" // Use the secret token you stored in gradle.properties as the password password = this.properties['MAPBOX_DOWNLOADS_TOKEN'] ?: "" } } } } これで先程指定したMAPBOX_DOWNLOADS_TOKENが読み込まれ、SDKバイナリがダウンロードされます。 アプリ設定 ドキュメントの通り設定してください。 PublicトークンをR.strings.xmlに設定します。アプリケーションに同梱されるトークンなのでpk.で始まるPublicトークンを設定します。本番のアプリケーションではトークンをローテーションさせられるように、自分の管理するサーバから取得するようにしても良いかもしれません。 src/main/res/values/strings.xml <resources> <string name="app_name">NavigationSDKSample</string> <string name="mapbox_access_token">MAPBOX_ACCESS_TOKEN</string> </resources Dependencyに追加します。 build.gradle dependencies { implementation "com.mapbox.navigation:android:2.0.2" } サンプルの作成 サンプルのコピペ Display a navigation UIにあるリンク先のコードをコピペすれば動く、と言いたいところですが、バージョンが合っていないことがあります。 v2.0.xをご利用の場合は以下のリンク先のソースをコピペしてください。 mapbox_activity_turn_by_turn_experience.xml TurnByTurnExperienceActivity.kt ディレクトリ構造は以下のようになります。 手直し appのbuild.gradleを開き、android内部に以下を追加 build.gradle android { compileSdk 31 ... buildFeatures { viewBinding true } ... } src/main/AndroidManifest.xmlを開き、activityを修正 src/main/AndroidManifest.xml ... <activity android:name=".TurnByTurnExperienceActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> ... TurnByTurnExperienceActivity.ktに対して以下の修正を実施 package名をMainActivityの一行目からコピペ importでpackage名由来の部分を同様に修正 実行 マップ長押しで行き先を選択 経路が設定され、ナビゲーション開始! Recenterボタンを押すとカメラがFollowingモードに遷移 成果物 今回作成したものはこちらにあります。 次回 まるっとコピペしたコードの内部を調査し、何が何をやっているのかを見ていきたいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Freezedの使い方

はじめにFreezedとは 簡単に言えばコピーメソッド等を含むImmutable(不変)なクラスを生成することができるパッケージのこと Freezedでコードを生成することで便利なメソッドがいくつか使用できるようになる。 ・copyWith nullを割り当てることが可能な複製メソッド ・== 同値であることの確認 ・toString 文字列化した時の結果 ・fromJson Mapからの変換 ・toJson Mapへの変換 上記のメソッドを使用して開発を楽にしましょう! Freezedの使用方法 インストール pubspec.yaml dependencies: // @freezed などを使うために必須 freezed_annotation: dev_dependencies: //コード生成するために必要 build_runner: freezed: // fromJson/toJson を生成させたい場合に必要になる json_serializable: Freezedクラスの書き方 例として、友人の情報をまとめたFriendクラスをfriend.dartファイルを作成して、 そこに定義していく。 friend.dart import 'package:freezed_annotation/freezed_annotation.dart'; // {ファイル名}.freezed.dart と書く part 'friend.freezed.dart'; //Freezed特有の書き方なので、スニペットを用意するのが良い @freezed class Friend with _$Friend { const factory Friend({ /// 友人の名前 required String name, //requiredで必須項目にする }) = _Friend; } 上記のコードのようにプロパティを必須項目にするには定義するプロパティの前にrequiredを記述する。 他にもnull許容にする場合、デフォルト値を設定する場合には下記のようにする。 null許容 String? name デフォルト値 @Default('qiita君') String name Freezedなクラスの定義が完了したら次にターミナルで下記のコマンドを入力し Build Runnerの機能を使用し、コードを生成する。 ターミナル flutter pub run build_runner build Freezedクラスの修正や変更があった時などに、変更ごとに上記のコードを入力するのが面倒だと思います、そのためにファイルの更新を検知して自動で再生成してくれるコマンドも用意されています。 簡単です。上記のコードの最後のbuildをwatchに変えるだけ! ターミナル flutter pub run build_runner watch コードを生成してからそれだけで終了せず、監視を行ってくれます。 Freezedクラスを編集してコード生成をすると、古い生成済みファイルと競合しエラーが発生することがあります。 delete-conflicting-outputs オプションを付けることで、競合ファイルを削除して再生成してくれます。 ターミナル flutter pub run build_runner watch --delete-conflicting-outputs Jsonから変換 または Jsonへの変換 をするために(fromJson/toJson) Jsonから変換 Jsonへ変換するためのメソッドを生成するためには Freezedだけではできないので 最初にpubspec.yamlに記入した json_serializable を使用し生成する。 JSON相互変換メソッドを生成させるには以下の2行を追加します。 part 'friend.g.dart' を追加 fromJson用のfactoryコンストラクタを追加 friend.dart import 'package:freezed_annotation/freezed_annotation.dart'; part 'friend.freezed.dart'; part 'friend.g.dart'; // 追加 @freezed class Friend with _$Friend { const factory Friend({ required String name, }) = _Friend; // {} ではなく =>(アロー)を使ってください factory Friend.fromJson(Map<String, dynamic> json) => _$FriendFromJson(json); } これで、 fromJson, toJson 両方のメソッドが生成されるようになりました! リントツールでのエラーが出る場合の対処方法 使用しているリントツールによっては、「コードがおかしいですよ」と怒られることもあるので、その場合は下記のように、 analysis_options.yaml で生成ファイルを対象外にしましょう。 analysis_options.yaml analyzer: exclude: - "**/*.freezed.dart" - "**/*.g.dart" 今回参考にさせて頂いた記事 主にRiverpodの使い方など本当にわかりやすく書かれています、 今回の記事は以下の記事のほんの一部に過ぎないので、 ぜひ参考にしてみて下さい!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む