20211201のAndroidに関する記事は11件です。

Flutterの開発環境構築方法(Mac)

はじめに 本記事は エムティーアイ Advent Calendar 2021 の1日目の記事です。 Flutterの開発環境を構築する方法を紹介します。 ちなみに業務ではFlutterを一切触っていません。 昨日行われた FlutterKaigi のハンズオンで初めてFlutterを触り、その準備時に行ったことを残します。 環境 OS:macOS Big Sur 11.6 ハード:MacBook Air (M1, 2020) Flutter:2.5.1 開発環境の構築 公式ドキュメントに沿ってFlutterの開発環境を構築します。 Flutter SDKのダウンロード 以下のページから、使いたいバージョンのFlutter SDKをダウンロードします。 特に決まりがなければ、Stable channelの最新を使うのがいいと思います。 ダウンロードが完了したら解凍します。 場所はどこでもいいですが、本記事では公式ドキュメント通り ~/development フォルダを作成して、そこに展開します。 以下はStable channelの 2.5.1 を解凍する例です。 $ cd ~ $ mkdir development $ cd development/ $ unzip ~/Downloads/flutter_macos_2.5.1-stable.zip Flutter SDKのパスを通す Flutter SDKを展開したら、パスを通します。 私はBashを使っているので .bash_profile に以下を追記します。 .bash_profile + export FLUTTER_HOME="${HOME}/development/flutter" + if [ -d "${FLUTTER_HOME}" ]; then + export PATH="${FLUTTER_HOME}/bin:$PATH" + fi .bash_profile を再読み込みし、 flutter --version でバージョンが出力されたらOKです。 $ source ~/.bash_profile $ flutter --version Flutter 2.5.1 • channel stable • https://github.com/flutter/flutter.git Framework • revision ffb2ecea52 (2 months ago) • 2021-09-17 15:26:33 -0400 Engine • revision b3af521a05 Tools • Dart 2.14.2 どうやらDartもFlutter SDKに同梱されているようです。 flutter doctorを実行する flutter コマンドが使えるようになったら flutter doctor を実行して、他にインストールすべき依存関係がないか確認します。 太字で×が付いたタスクがあればそれを実行します。 $ flutter doctor Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel stable, 2.5.1, on macOS 11.6 20G165 darwin-arm, locale ja-JP) [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3) [!] Xcode - develop for iOS and macOS ✗ 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 see https://guides.cocoapods.org/using/getting-started.html#installation for instructions. [✓] Chrome - develop for the web [!] Android Studio ✗ Unable to find bundled Java version. [✓] Android Studio (version 2020.3) [✓] VS Code (version 1.60.0) [✓] Connected device (1 available) ! Doctor found issues in 2 categories. 最初は4つ×があったのですが、2つ解決したので2つのみ×が出力されています。 でも解決した2つとも覚えているので、それらの対応を紹介します。 ちなみに私はXcodeとAndroid Studioをインストール済でした。 未インストールの人は、インストールから行ってといわれると思います。 Android SDK Command-line Toolsがインストールされていない 以下のエラーが出力された場合、Android SDK Command-line Toolsがインストールされていません。 [!] Android toolchain - develop for Android devices (Android SDK version 30.0.3) ✗ cmdline-tools component is missing Run `path/to/sdkmanager --install "cmdline-tools;latest"` See https://developer.android.com/studio/command-line for more details. Android Studioから「Android SDK Command-line Tools (latest)」をインストールすればOKです。 Androidのライセンスに同意していない 以下のエラーが出力された場合、Androidのライセンスに同意していません。 [!] Android toolchain - develop for Android devices (Android SDK version 30.0.3) ! Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses エラーの内容通り flutter doctor --android-licenses を実行し、必要なライセンスにすべて同意します。 $ flutter doctor --android-licenses 3 of 7 SDK package licenses not accepted. 100% Computing updates... Review licenses that have not been accepted (y/N)? y Accept? (y/N): y 再度コマンドを実行して「All SDK package licenses accepted.」が出力されればOKです。 $ flutter doctor --android-licenses All SDK package licenses accepted.======] 100% Computing updates... CocoaPodsがインストールされていない 以下のエラーが出力された場合、CocoaPodsがインストールされていません。 [!] Xcode - develop for iOS and macOS ✗ 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 see https://guides.cocoapods.org/using/getting-started.html#installation for instructions. 私はrbenv + BundlerでCocoaPodsを管理したいので、こちらのエラーは無視しました。 Flutterによる開発ではCocoaPodsをグローバルインストールするのが一般的なのでしょうか? もし知っている人がいたら教えてほしいです。 Android Studioに同梱されているJDKが見つからない 以下のエラーが出力された場合、Android Studioに同梱されているJDKが見つかりません。 [!] Android Studio ✗ Unable to find bundled Java version. 結論からいうと、こちらのエラーは解決できませんでした。 解決方法をご存知の人がいたら教えてほしいです。 参考までに試したことを残しておきます。 どこかのタイミングでAndroid Studioに同梱されているJDKのパスが変わったのが原因だと思い、その対応を行いました。 - /Applications/Android\ Studio\.app/Contents/jre/jdk/Contents/Home + /Applications/Android\ Studio\.app/Contents/jre/Contents/Home 私はAndroidアプリ開発以外でJavaを使わないため、 .bash_profile で JAVA_HOME にAndroid Studioに同梱されているJDKをセットしてパスを通します。 以前の jdk を含んだパスを指定します。 .bash_profile + export JAVA_HOME=/Applications/Android\ Studio\.app/Contents/jre/jdk/Contents/Home + if [ -d "${JAVA_HOME}" ]; then + export PATH="${JAVA_HOME}/bin:$PATH" + fi このままだとパスが見つからないので、以前のパスにシンボリックリンクを貼ります。 $ cd /Applications/Android\ Studio\.app/Contents/jre $ ln -s ../jre jdk $ ln -s "/Library/Internet Plug-Ins/JavaAppletPlugin.plugin" jdk $ cd - これで JAVA_HOME をセットしてパスを通せたのですが、それでも解決されませんでした。なぜでしょうか…。 Android Studioプラグインのインストール Android StudioにFlutterのプラグインをインストールします。 プラグインの「Marketplace」タブを開き、「flutter」で検索すると簡単にインストールできます。 Dartのプラグインが必要だといわれるので、「Install」を押下します。 Android Studioを再起動し、「Installed」タブに「Dart」と「Flutter」があればOKです。 ちなみにどちらのプラグインもOSSで開発されています。 おまけ: Flutter SDKの管理ツール 本記事ではFlutter SDKを手動で管理していますが、それだと複数のプロジェクトで異なるバージョンを使いたいときに困ります。 Flutterには fvm や asdf などの管理ツールがあり、これらを使うことで手動管理のデメリットを解消できます。 TwitterでFlutter SDKをどのように管理しているかアンケートを取ってみました。 結果はfvmが最も多かったです。 ただasdfも流行ってきているとのことなので、各管理ツールのメリットやデメリットを調査し、プロジェクトに合ったツールを選定するのがよさそうです。 おわりに まだ不十分なところもありますが、Flutterの開発環境が構築できました! FlutterでUIを気持ちよく組み立てていきましょう 以上 エムティーアイ Advent Calendar 2021 の1日目の記事でした。 参考リンク https://twitter.com/the_uhooi/status/1465571548463464451?s=20 1. Flutter 環境構築 · FlutterKaigi/atomic_design_handson Wiki flutter doctorで「Unable to find bundled Java version.」となる場合の解決法
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Androidのゲーム開発まとめ

背景 どうも”おもり”です。 私の最近のハマりは、「ちいかわ」です。 こんな可愛らしいキャラクターを自分で作って、Androidアプリでゲーム化したいなーという野望があるのです。 ちょうど、?のようなアプリがあることも知って、可愛らしさに舌を巻きました。 そんな訳で、Androidでゲーム開発をするスキルを頑張ってみようと思った訳です。今月ちょっと頑張ってみます。 対象読者 Androidでゲーム開発をしたことが無い人 Androidアプリ開発はしているが、ゲーム開発にも興味がある人 Androidでゲーム開発を始めるには? まず初めに辿り着くのは、こちらの記事でしょう。 Android Game Development Kit(AGDK)の中にゲーム開発で必要なものが詰まっている。 UnityやUnreal Engine4などのゲームエンジンを使ってゲーム開発ができる。 Youtubeなどで動画を探してみても、良さそうな勉強教材が見つかりません。 公式ドキュメントを読み込んで、ノウハウを学んでいくしかなさそうですね。 どのゲームエンジンを使うのが良いのか? ゲームエンジンには、UnityとUnreal Engine4などがあります。これ以外は特に見るつもりはありません。 この記事がとても読みやすかったです。 Unity ゲームアプリ開発の主流 開発のための情報が豊富 ゲームエンジンのシェアがNo.1 言語はC# Unreal Engine PCゲーム開発の主流 描画の綺麗さはUnity以上 Unreal Engine5の登場が控えており勢いがある 言語はC++ https://note.com/withid/n/n9a38e91de609 こちらの記事の以下の文章を見る限り、私のやりたいこと的には、Unityなのだなと納得。 私は業務でC++を4年間使い続けている関係もあり、Unreal Engineを使いたいなーって思ってたのですが、 やっぱりUnityなのかーって感じですね。VR技術も身に着けたいと感じていた今日この頃。Unity頑張ろう。 UnityでAndroidゲーム開発を始めるには? 早速、Unityをダウンロード。 Youtubeにも参考になりそうな動画が見つかったので、これを通勤中に見ながら勉強を開始します。 あとは、Unityのマニュアルを読みながら実践あるのみ。 Androidゲーム開発をする上で 追加予定。。。 まとめ Androidのゲーム開発をする上で、Unityがベストアンサーだと思います。 AGDKとUnityを連携させて、ゲーム開発を始めていきましょう!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Android Studioでjdkを8→11にアップデートしたらComponenCallbacksにアクセスできませんというエラーに遭遇した

先日Android Studioでjdkを8→11にアップデートした際に、 ComponentCallbacksにアクセスできませんというビルドエラーに遭遇しました。 エラーが出ている所を見に行っても何も警告等は出ておらず、何かライブラリが足りていないのかと長時間ハマってしまいました。 結論としては、gradleバージョンが低い事が原因だったようです。 File > ProjectStructure > Project と遷移していくと、Android Gradle Plugin VersionとGradle Versionを設定画面に遷移できます。 ここでこれらのバージョンを最新のものにしてあげると無事ビルドができるようになりました。 謎のビルドエラーに阻まれた時は、まずクリーンビルドやInvalidate Caches。 それらがダメであればGradleやPluginのバージョンを見直そうねという話ですね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

NrealLightアプリ実行中にログを確認する

NrealLightとは NrealLightとはARグラスの一種です。 このデバイスのログを、アプリ実行中に取得したいというのが、今回のお話です。 NrealLightアプリ実行中にログを確認する NrealLightアプリのOSはAndroidなので、ログを確認するにはlogcatが必要です。 ただし、スマートフォンのUSBポートはグラスに接続されており、PCにつなげることはできません。 そこで、PCと無線でつなげてみることにしました。 検証環境 グラスデバイス: NrealLight スマートフォンOS: Android 11 スマートフォンのワイヤレスデバッグを有効にする 開発者向けオプションを有効にした状態で、図のように ワイヤレスデバッグ のトグルを有効にします。 ワイヤレスデバッグを有効にするかどうか聞かれるので、 許可 をタップします。 次に、ワイヤレスデバッグのトグルではなく、文字をタップします。 以下の画面に遷移するので、 ペア設定コードによるデバイスのペア設定 をタップします。 すると、ペアリングコードやIPアドレス等の情報が表示されるのでメモします。 adbでペアリングする さきほどメモした情報をもとに以下のコマンドを実行してください。 adb pair <スマートフォンのIPアドレス>:<ポート> Enter pairing code: と表示されたら、メモしたコードを入力してください。 Successfully paired to と表示された成功です! Failedになった場合 Failed: Unable to start pairing client. と出た場合、スマートフォンとPCが同一LANにない可能性があります。 ping コマンド等で疎通を確認してください。 adbで接続する ペアリングができたら、以下のコマンドで接続してください adb connect <スマートフォンのIPアドレス>:<ポート> 対象のコンピューターによって拒否されたため、接続できませんでした。というエラーになった場合 対象のコンピューターによって拒否されたため、接続できませんでした。 (10061) というエラーが出た場合、スマートフォンをUSBでPCに接続して、以下のコマンドを実行すると接続することがあります。 adb tcpip <ポート> logcatを実行する 以下のコマンドでlogcatを実行できます。 adb logcat さいごに 本記事作成にあたり、以下を参考にさせていただきました。ありがとうございます。 Unity Documentation / ログファイル Android Debug Bridge Android 11 wifi adb error "Unable to start pairing client"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UnityのAndroid SDKにAPIレベル30のSDKツールを導入する

Google Play ConsoleでAndroidアプリをリリースしようとしたらエラーになった ターゲットのAPIレベルが29のアプリをリリースしようとしたところ、エラーになりました。 どうやら、ターゲットレベルが30以上じゃないとダメみたいです。 どうやって30をインストールするんだっけ? ということで、Android SDKに新しいAPIレベルのツールを導入する手順を、備忘録として残します。 今回は Unity 2019.3.6f1 に API level 30 を導入します。 Unityが参照している Android SDK のパスを確認する Unity の Preferences > External Tools > Android SDK Tools installed with Unity 欄に Android SDK のパスが記載されています。 今回の私の環境では、 C:\Program Files\Unity\Hub\Editor\2019.3.6f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK でした。 Android SDK に API level 30 を導入する 管理者権限でコマンドプロンプトを開きます。 カレントディレクトリを先程の SDK フォルダにします。 cd "C:\Program Files\Unity\Hub\Editor\2019.3.6f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK" ※コマンドは一例です。SDKフォルダーへのパスはご自身の環境に合わせてください。 以下のコマンドで API level 30 をインストールできます! tools\bin\sdkmanager "platform-tools" "platforms;android-30" 以下のように表示されたら y を入力しましょう! Accept? (y/N): y ゲージが 100% になったら成功です! さいごに 本記事作成にあたり、以下を参考にさせていただきました。 https://developer.android.com/studio/command-line/sdkmanager?hl=ja
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

禁断の速読術の習得方法!速読英単語のアプリを個人開発してリリースした話

禁断の速読術の習得方法 速読のアプリというのは、大体高額のセミナーに参加したり、速読をするための訓練が必要な事がほとんどだと思います。 そんな中無料でアプリをリリースしたので、皆さんに使って貰いたいので、記事を書く事にしました。 まずリリースしたアプリはこちら 現在は、google playストアにしかリリースしていません。 androidユーザーが登録してくれたら、iOS版版も出そうと思っています。 開発環境はMonacaです Monacaとは、「ハイブリッドアプリ」を作成することができるWEBサービスです。ネット上にアプリの開発環境を用意してくれるので、面倒な環境構築は一切必要ありません。 また、サンプルのアプリもいくつか用意されているので、簡単にアプリ開発を体験することができます。 私はここの最小限のアプリケーションを作るから、JQueryとFont Awesomeをダウンロードして www配下に設定してアプリケーションを作成しました。 ハイブリッドアプリとは「iOS」「Android」「WEB」のどのデバイスでも動作するWEBアプリのことです。「HTML5」「CSS」「JavaScript」の3つのWEBプログラミング言語を使ってアプリを作ります。 興味がある方は、Monacaおススメです。 使い方 使い方は簡単で、再生ボタンを押したら、速読が始まります。 実際に操作している動画はこちら 読み上げる間隔を変更する場合は、読み上げる間隔左ほど早くなりますのしたのバーを一番左にすると、 速読する速度が変わります。 速度を変更するには、バーを動かして、再生ボタンを押すことで、速度の調整が出来ます。 このバーがとても便利で、HTMLのタグ< input type="range" > と入力するだけで、速度などの値を変更することが出来ます。 詳細な使い方は、下記のようになります。 下に使い方のリンクも張っているので、気になる方は要チェックです。 <div> <input type="range" id="volume" name="volume" min="0" max="11"> <label for="volume">Volume</label> </div> 要望受け付けます 文字の色も変更出来ます。もっと色の種類が必要だという声があったら、追加しますので、こちらにコメントして下さい。 速読する文字の大きさも変更出来ます。 これは、文字の大きさのバーを右にする程大きくなります。 速読の再生をしている場合でも色の変更と文字の大きさの変更は出来ます。 色の種類は現在Black、Red、Blue、Greenの4種類があります。 文字の大きさを変えるコードの説明 文字の大きさは最大100PXまで大きく出来ます。 コード的には、スライダーが変更される毎にmain_nowのIDの文字サイズを変更しています。 <input type="range" id="text-slider" value="30" min="1" max="100" step="1" oninput="onTextSliderInput(this.value)"> <!-- 変更する文字の出力先 --> <div id="main_now" class="main_now"></div> function onTextSliderInput(size) { textSize = size; document.getElementById("text-slider").value = textSize; document.getElementById("main_now").style.fontSize = textSize + "px"; } HTMLの参考例 一番簡単な文字のサイズを変えるコードはこちら 下のHTMLをコピーして、HTMLファイルにすると実際に文字の大きさを変える事が出来ます。 <html> <head> </head> <body> <script> function onTextSliderInput(size) { textSize = size; document.getElementById("text-slider").value = textSize; document.getElementById("main_now").style.fontSize = textSize + "px"; } </script> <input type="range" id="text-slider" value="30" min="1" max="100" step="1" oninput="onTextSliderInput(this.value)"> <!-- 変更する文字の出力先 --> <div id="main_now" class="main_now">大きくするテキストの例</div> </body> </html> 使ってみて、こんな機能があったら良いなどの要望がありましたら、コメントしてくれると嬉しいです。 Androidユーザーは是非とも速読体験をして下さいね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Kotlinアプリケーション開発に、NoSQLドキュメント指向モバイルデータベースCouchbase Liteを使ってみる

はじめに 本稿では、Kotlinアプリケーション開発に、NoSQLドキュメント指向モバイルデータベース Couchbase Liteを使うための具体的な方法について解説します。 本稿では、Couchbase Lite 3.0.0ベータ版をKotlinアプリケーションで利用する際の動作確認までを行います。 Couchbaseをモバイルアプリケーションで利用する意義については、以下の記事をご参考ください。 確認環境 macOS Catalina Version 10.15.7 Android Studio 4.1.3 実行手順 プロジェクト作成・Couchbase Liteインストール Android Studioで新しい「Empty Activity(空のアクティビティ)」プロジェクトを作成します build.gradleファイル編集 新しく作成したプロジェクトで、アプリケーションレベルのbuild.gradleファイルを編集します。 androidセクション androidセクションのminSdkVersionを22にします。 今回検証したプロジェクトのbuild.gradleファイルの全体を示します。minSdkVersion以外は、変更していませんが、compileOptionsやkotlinOptionsのバージョンに注意してください。 android { compileSdkVersion 30 buildToolsVersion "30.0.3" defaultConfig { applicationId "com.example.cbl_kotlin" minSdkVersion 22 targetSdkVersion 30 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } } repositoriesセクション repositoriesセクションに以下を含めます。 repositories { maven { url 'https://mobile.maven.couchbase.com/maven2/dev/' } // ... 省略 } dependenciesセクション dependenciesセクションに以下を含めます。 dependencies { implementation 'com.couchbase.lite:couchbase-lite-android-ee-ktx:3.0.0-beta02' // ... 省略 } 以上の変更を加えた後に、プロジェクトをビルドすると、Couchbase Liteがプロジェクトにプルダウンされます。 プログラミング・実行結果確認 MainActivityファイル編集 インポート文として、下記を追加します。 import android.content.Context import android.util.Log import com.couchbase.lite.* MainActivityクラスを以下のように編集します。 class MainActivity : AppCompatActivity() { private var TAG = "CBL-TEST" private var cntx: Context = this override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Couchbase Lite 初期化 CouchbaseLite.init(cntx) Log.i(TAG,"Couchbase Lite 初期化完了") // データベース作成 Log.i(TAG, "データベース作成開始") val cfg = DatabaseConfigurationFactory.create() val database = Database("kotlindb", cfg) val docId = "test" // ドキュメント作成 var mutableDoc = MutableDocument(docId).setString("type", "user") // ドキュメント保存 database.save(mutableDoc) // ドキュメント取得、変更、保存 mutableDoc = database.getDocument(docId)!!.toMutable().setString("name", "田中") database.save(mutableDoc) // ドキュメント取得、ログ出力 val document = database.getDocument(docId)!! Log.i(TAG, "ドキュメントID : ${document.id}") Log.i(TAG, "名前 : ${document.getString("name")}") // クエリ val rs = QueryBuilder.select(SelectResult.all()) .from(DataSource.database(database)) .where(Expression.property("type").equalTo(Expression.string("user"))) .execute() Log.i(TAG, "ドキュメント数 : ${rs.allResults().size}") } } ビルドし、エミュレーターで実行します。 ログ logcatウィンドウに以下のようなログが表示されます。 データベースファイル メニューから、Device File Explore(View > Tool Window > Device File Explore)を開きます。 「Name」セクションのdata > dataを開きます。 アプリケーションのパッケージ以下のfilesに下記のように作成したデータベース(フォルダー)を確認することができます。 最後に 本稿では、Kotlinアプリケーション開発のために、プロジェクトにCouchbase Liteをダウンロードし、基本的な操作が行えるところの確認までを行いました。 モバイルアプリケーション開発に組込データベースを使った経験のある方であれば、以降の応用は、比較的簡単に可能かと思います。 最後に、さらなるステップに進むための情報を示して、本稿の締め括りとしたいと思います。 Couchbase Liteについての記事を以下の投稿で整理していますので、ご関心に応じて、参照してみてください。 Kotlinについては、まず今年2021年に発表されたビデオを紹介します。 Kotolinではなく、Android Javaが利用されていますが、Couchbase Liteを用いた以下のようなチュートリアルが存在します。 こちらも、Kotolinではなく、Android Javaが利用されていますが、サンプルアプリケーションを動作させる環境の構築を通じて、Couchbase Lite利用のみではなく、Couchbase Serverとのデータ同期までをカバーした、以下のチュートリアルがあります。 上記のチュートリアルの内容をベースに日本語化したものを下記で確認いただけます。 Kotlinを使ったチュートリアルとして、Couchbase Liteではなく、Couchbase Serverとの連携を扱ったものとして以下があります。 本稿で扱っていない、Couchbase Serverについては、日本語で読むことができるまとまった情報として、次の拙著を紹介させていただきます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity Android 画面設定 ナビゲーションバーの表示

0.0 はじめに Unityで作ったアプリのデフォルト設定はナビゲーションバーが表示されません。ナビゲーションバーとは下に出てくる丸や三角や四角のボタンです。この設定では下からスワイプすることで表示はできますが、しばらくすると消えてしまいます。この記事では最初からナビゲーションバーを表示する方法、ナビゲーションバーを保持する方法を書いています。 1.0 ナビゲーションバー常時表示 下記を最初のシーン入れます。これでアプリが立ち上がったらすぐにナビゲーションバーが表示されます。 Test.cs void Awake(){ Screen.fullScreen = false; } 2.0 戻るボタンの有効化(◁ボタン) 戻るボタンは1.0を設定しただけでは有効になりません。下記を各シーンに入れると戻るボタンを有効にして、アプリを終了させることができるようになります。 Test.cs void Start () { Input.backButtonLeavesApp = true; }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Java]Android Fragment間のデータ受け渡し Bundle vs ViewModel

目的 Android, Javaで開発するにあたり、Fragment間のデータ受け渡しにBundleとViewModelどちらを使うべきか指標を明示する。 ※ただしデータの値は変更しない前提です。 結論 Bundle:Fragment間で受け渡すデータ数が少ない場合 ViewModel:Fragment間で受け渡すデータ数が多い場合 のように使い分けるのが良いと思います。 はじめに 初めてAndroid開発をしたときに、Fragmentから別Fragmentにデータを受け渡すとき、メジャーな方法としてBundleとViewModelがあると知りました。 両方使ってみて、それぞれの利点・欠点が少し分かったので、まとめてみます。 ちなみに筆者は最初はBundleを使いまくっていたのですが、以下に記載する欠点により、ViewModelをメインで使うようになりました。 Bundle vs ViewModel BundleとViewModelの利点・欠点をまとめます。 Bundle ViewModel 利点 データの定義が不要データのスコープが狭い データ名/型の管理がシンプルFragmentへの渡し不要 欠点 データ名/型の管理が煩雑Fragmentへの渡し必要 データの定義が必要データのスコープが広い 以下、それぞれ説明していきます。 Bundle 利点 データの定義が不要 BundleはputStringやputIntなどでデータ名を指定し値設定、getStringやgetIntなどでデータ名を指定し値取得ができます。 FirstFlagment.java public class FirstFlagment extends Fragment { ... private void moveFragment() { Bundle bundle = getArguents(); bundle.putInt("Apple", 100);// ★値設定 SecondFragment secondFragment = new SecondFragment(); SecondFragment.setArguments(bundle); // フラグメント遷移 getChildFragmentManager() .beginTransaction() .add(R.id.first_layout, secondFragment) .commit() } ... } SecondFlagment.java public class SecondFlagment extends Fragment { ... @Override public void onViewCreated(View view, Bundle bundle) { Bundle bundle = getArguents(); int value = bundle.getInt("Apple");// ★値取得 ... } ... } 上記のように、データ名を指定して簡単に値を設定し渡すことができます。 データのスコープが狭い 上記の例のように、Bundleを渡したフラグメントのみ、該当データを取得できるため、データのスコープは狭く制限できていると言えます。 欠点 データ名/型の管理が煩雑 データの種類が増えてくると、当然データ名が複数必要になります。 また、各データの型が違う場合は、どのデータがどの型か、の管理も必要になります。 要は、データの種類が増えると、取り出すときにどんなデータ名と型で登録したっけ?と分かりづらくなっちゃうってことです。 以下は、データの設定と取得でデータ名/型が一致していないため、NGとなるケースです。 データの設定 bundle.putInt("Apple", 30); bundle.putString("Orange", "30"); bundle.putInt("Lemon", 60); データの取得 int apple = bundle.getInt("Apple");// ← OK int orange = bundle.getInt("Orange");// ← NG: getStringで取得していない int lemon = bundle.getInt("Lemo");// ← NG: データ名誤り Fragmentへの渡し必要 FragmentのsetArgumentsでBundleを渡す必要があります。 これを忘れると、次のFragmentでBundleを使えません。 データの取得 Bundle bundle = getArguents(); bundle.putInt("Apple", 100); SecondFragment secondFragment = new SecondFragment(); SecondFragment.setArguments(bundle);// ← これを忘れるとデータを渡せない Fragment 利点 データ名/型の管理がシンプル ViewModelの属性としてデータを定義するため、データ名(変数名)と型をシンプルに管理できます。これで、データ名と型はこのクラスを見れば間違いなく分かります。 MyViewModel.java public class MyViewModel extends ViewModel { public int apple; public String orange; public int lemon; ... データの設定/取得は、ViewModelProviderでViewModelを取得して実行できます。 FirstFlagment.java public class FirstFlagment extends Fragment { ... private void moveFragment() { MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class); viewModel.apple = 100;// ★値設定 SecondFragment secondFragment = new SecondFragment(); // フラグメント遷移 getChildFragmentManager() .beginTransaction() .add(R.id.first_layout, secondFragment) .commit() } ... } SecondFlagment.java public class SecondFlagment extends Fragment { ... @Override public void onViewCreated(View view, Bundle bundle) { MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class); int value = viewModel.apple;// ★値取得 ... } ... } Fragmentへの渡し不要 上記コードの通り、ViewModelのデータ取得/設定はViewModelProvider経由で行うので、bundleのように次フラグメントへの渡し忘れは起きません。 欠点 データの定義が必要 上記のコード例の通り、ViewModel継承したクラスを定義し、受け渡すデータをすべて属性として定義する必要があります。 そのためBundleと比べると、ひと手間が必要で、1,2個だけデータを受け渡したいときはわざわざViewModelを作るのは面倒に感じます。 データのスコープが広い ViewModelは、ViewModelProviderを用いてどのフラグメントからも取得可能です。 よって、データのスコープが広くなっていると言えます。 チームで開発をしている場合、ViewModelの値がどこかで書き換えられているかもしれませんので、注意して使う必要があります。 私の場合、アプリ全体を一人で開発したため、ViewModelは読み取り専用と決めて使ったため、このデメリットは問題になりませんでした。 ViewModelProvider経由でどこからでもデータ取得可能 MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class); まとめ Bundle  データの定義が不要でスコープも限定できるが、  データ名/型の管理が煩雑でFragmentへの渡し必要。  ⇒Fragment間で受け渡すデータ数が少ない場合 に使い易い。 ViewModel  データ名/型の管理がシンプルでFragmentへの渡し不要だが、  データの定義が必要でデータのスコープが広い。  ⇒Fragment間で受け渡すデータ数が多い場合 に使い易い。 と結論づけました。 最後に 筆者はAndroid開発に携わって1年ほどです。 まだまだ知見不足の点があるかと思いますので、お気づきの点はご指摘くださると助かります。 参考 https://developer.android.com/topic/libraries/architecture/viewmodel?hl=JA#sharing https://qiita.com/m-coder/items/3a8e66d49f2830b09bf4
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

android端末をひかり電話の子機に設定する

不要になったandroid端末をひかり電話の子機に設定した話(備忘録) ホームゲートウェイ/ひかり電話ルーターの設定 使ったルーター PR-500MI 設定 電話回線>内線設定 で未登録の内線番号の[編集]をクリック 内線番号:メモする ニックネーム:わかりやすいように端末名などを設定 端末属性:[音声専用端末]に設定([通常端末]でもよいと思う) MACアドレス:端末のMACアドレスを設定(設定しなくてもよい) ダイジェスト認証:[行う]に設定 ユーザID:メモする パスワード:メモする(変更してもよい) android端末の設定 使った端末 zenfone 4 Max 設定 設定>通話設定>通話アカウント>SIPアカウント で[+]をタップして編集画面を開く ユーザ名:メモした内線番号を設定 パスワード:メモしたパスワードを設定 サーバー:ホームゲートウェイ/ひかり電話ルータのIPアドレスを設定 オプション設定を開く 認証ユーザ名:メモしたユーザIDを設定 ポート番号:5060 伝送方式:UDP 以上を設定して[保存]をタップ 設定>通話設定>通話アカウント SIP通話の使用:子機専用なら[すべての通話]、SIM回線と選択したいなら[SIP通話のみ]を選択 着信を受ける:着信を受けたいならチェックを入れる 以上
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

カメラ映像を出さずに画像データを取得&画像解析

本記事はAndroid Advent Calendar 2021の2021/12/01分です。 はじめに 最近流行りのAI1を用いスマホのカメラから取得した映像に対して処理するアプリを作りたいときに、サンプルを探すと基本的にカメラで撮影した映像に処理結果をオーバーレイした画面が表示されたものばかりでてきます。 しかし、スマホのディスプレイにメインコンテンツ(≠カメラ映像)を映しつつスマホのカメラで撮影した映像をAIで処理したいというニーズもそこそこあると思います。 あやふやな記憶なんですが、5,6年ほど前はカメラを使用する際にはカメラから取得した映像を画面に表示することが必須で、表示しない場合はカメラ機能は使えず仕方なく画面に1pxだけ表示するSurfaceViewを使ったりしたような記憶があります。 しかしこのAI1全盛時代においてさすがにカメラ映像を出さずにも使えるだろうと思い試してみました。 結論 CameraX APIのImageAnalysis.Analyzerを使うことでできます。 実際にやってみる それでは実際にやってみます。 今回はTensorFlow Liteを用いてUI上のボタンを押すとカメラに写った物体を判別してみます。 AIモデルに関してはTensorFlow LiteのExampleで公開されているものを使用しました。 TensorFlow Lite及びモデルともに今回の本題ではないので詳しい説明はないです。 1.TensorFlow LiteとCameraXのインポート モジュールのbuild.gradleに追加するだけです。 ついでにパッケージング時にモデルまで圧縮されると当然動かなくなってしまうので、モデルファイルを圧縮しない設定もしておきます。 build.gradle ~~~~ 略 ~~~~~ android { ~~~~ 略 ~~~~~ aaptOptions { noCompress "tflite" } } ~~~~ 略 ~~~~~ dependencies { ~~~~ 略 ~~~~~ implementation 'org.tensorflow:tensorflow-lite:2.7.0' implementation 'org.tensorflow:tensorflow-lite-gpu:2.7.0' implementation 'org.tensorflow:tensorflow-lite-support:0.3.0' def camerax_version = "1.0.2" implementation "androidx.camera:camera-core:${camerax_version}" implementation "androidx.camera:camera-camera2:${camerax_version}" implementation "androidx.camera:camera-lifecycle:${camerax_version}" implementation "androidx.camera:camera-extensions:1.0.0-alpha31" } 2.TensorFlow Lite用のモデルの取り込み TensorFlow Liteでは、学習済みモデルがいくつか公開されています。 今回はその中のObject Detection(物体検出)をやってみます。 まずはモデルが公開されているのでダウンロードします。 次にダウンロードしたモデル(lite-model_ssd_mobilenet_v1_1_metadata_2.tflite)をAndroidプロジェクトにインポートします。 インポート方法はAndroidStudioでインポートしたいmoduleを右クリック->New->Other->TensorFlow Lite Modelをクリック。 クリックするとどのモデルをインポートするか聞かれるので、先程ダウンロードしたファイルを選択します。 Finishを押した後下記のようにモデルの詳細が出てくれば取り込み成功です。 3.CameraXを用いてデータを取得する あとは、CameraXを用いてデータを取得しAIモデルに流し込むという流れになります。 まずはCameraXで画像データを取得するところをやってみます。 まずは意外と忘れるAndroidManifestにカメラのPermissionを記載 AndroidManifest.xml <uses-permission android:name="android.permission.CAMERA" /> アプリを起動したタイミング等でカメラのPermissionをユーザーから取得 今回はPermissionsDispatcherを用いて、起動したら直ぐにユーザーから取得します。(挙動確認アプリなので特に取得できなかったときなどは考えません) MainActivity.kt @RuntimePermissions class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) hogehogeWithPermissionCheck() <- ここで取得してしまう ~~~~ 略 ~~~~ } @NeedsPermission(Manifest.permission.CAMERA) fun hogehoge() { // DO nothing } Camera Providerの取得 此処から先はおまじないCameraXを使うボイラープレートの意味合いが結構強いです。 MainActivity.kt private val cameraExecutor by lazy { Executors.newSingleThreadExecutor() } private suspend fun getCameraProvider(): ProcessCameraProvider = suspendCoroutine { continuation -> ProcessCameraProvider.getInstance(this).apply { processCameraProvider = this addListener({ continuation.resume(get()) }, cameraExecutor) } } 使用するカメラの指定 今回はカメラは背面固定 MainActivity.kt private fun buildCameraSelector(): CameraSelector = CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_BACK) .build() CameraXにデータの利用目的を画像解析に設定 今回はカメラデータの利用目的が画像解析(Analyze)なのでImageAnalysisを使います。 CameraX APIでは、カメラで取得した画像映像データをどのような目的で使用するか(UseCaseと呼ぶ)を指定する必要があります。 現在は下記の3つのUseCaseが用意されています。 プレビュー: プレビュー表示用 画像解析: 画像解析用 画像キャプチャ: 写真保存用 これらのUseCaseは複数個組み合わせることができますが今回はあえてここでImageAnalysis(画像解析)だけを使用することでプレビュー無しでのカメラ利用ができるというわけです。 ある意味この記事はここ以外・・・ また、ここでどの程度のクオリティの画像を取得するかの指定なども行います。 MainActivity.kt private val imageAnalyzer by lazy { ImageAnalysis.Builder() .setTargetResolution(Size(640, 480)) .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST).build() } カメラの画像データの取得 上記で作成したImageAnalysisインスタンスに対して、setAnalyzerメソッドを呼ぶことでカメラから画像データを取得します。 コールバックを登録し、取得できたら呼ばれるタイプなのでメソッドを呼んだ瞬間のデータが取れるわけではないというところは注意です。 MainActivity.kt private suspend fun setAnalyzer(executor: Executor): ImageProxy { return suspendCoroutine { continuation -> imageAnalyzer.setAnalyzer(executor, { image -> continuation.resume(image) }) } } 上記をまとめて実行 CameraXまわりのAPIはコールバックが多く、そのまま実装するとコールバック地獄になりがちなので、KotlinCoroutineのsuspendCoroutineを使って単純なメソッドっぽくラップしています。 コードは載せていませんが、適当なボタンを作って押されたらこのメソッドを呼べばいいと思います。 MainActivity.kt @SuppressLint("UnsafeOptInUsageError") private fun doJudge() { var resultImage: ImageProxy? = null lifecycleScope.launch { try { cameraProvider = getCameraProvider() val selector = buildCameraSelector() val camera = cameraProvider?.bindToLifecycle( this@MainActivity, selector, imageAnalyzer ) ?: return@launch resultImage = setAnalyzer(cameraExecutor) // ここで取れた resultImage の中に画像データが入っている resultImage!!.close() resultImage = null cameraProvider?.unbindAll() cameraProvider = null } catch (e: Exception) { } finally { cameraProvider?.unbindAll() cameraProvider = null resultImage?.close() } } } 4.TensorFlow Liteを使って画像解析 やっとカメラから画像データが取れたのでこれの中に何が写っているかを解析したいと思います。 モデルが受け取れる形式に変換 CameraXから取得できる画像データはImage(android.media.Imageクラス)形式なのですが、これをそのまま先程取り込んだモデルに入力として渡すことができません。 そこでまずはモデルに入力できる形式に変換します。 また、今回のモデルは、300px x 300px以下の画像サイズでのインプットになるので、それに合わせた縮小処理も必要となります。 AndroidのTensorFlow LiteのサポートライブラリにはBitmapからの入力をサポートしてくれるメソッドがあるので今回は300px x 300px以下のBitmap画像に変換する処理を行います。 MainActivity.kt private fun toBitmap(image: Image): Bitmap? { val planes: Array<Image.Plane> = image.planes val yBuffer: ByteBuffer = planes[0].buffer val uBuffer: ByteBuffer = planes[1].buffer val vBuffer: ByteBuffer = planes[2].buffer val ySize: Int = yBuffer.remaining() val uSize: Int = uBuffer.remaining() val vSize: Int = vBuffer.remaining() val nv21 = ByteArray(ySize + uSize + vSize) yBuffer.get(nv21, 0, ySize) vBuffer.get(nv21, ySize, vSize) uBuffer.get(nv21, ySize + vSize, uSize) val yuvImage = YuvImage(nv21, ImageFormat.NV21, image.width, image.height, null) val out = ByteArrayOutputStream() yuvImage.compressToJpeg(Rect(0, 0, yuvImage.width, yuvImage.height), 75, out) val imageBytes: ByteArray = out.toByteArray() val croppedBitmap = Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888) val src = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size) // 直接縮小したBitmapを作る方法がなさそうなのでCanvas経由で作る val canvas = Canvas(croppedBitmap) val matrix = getTransformationMatrix(src.width, src.height, 300, 300) canvas.drawBitmap(src, matrix, null) return croppedBitmap } // 縮小率を求めてCanvasに書き込むときの倍率指定Matrixを作る private fun getTransformationMatrix( srcWidth: Int, srcHeight: Int, dstWidth: Int, dstHeight: Int ): Matrix { val matrix = Matrix() val scaleFactorX = dstWidth.toFloat() / srcWidth.toFloat() val scaleFactorY = dstHeight.toFloat() / srcHeight.toFloat() val scaleFactor = min(scaleFactorX, scaleFactorY) matrix.postScale(scaleFactor, scaleFactor) return matrix } モデルにデータを入力&出力取得 モデルにデータが入れれるようになったので、そのまま渡します。 AndroidでTensorFlow Liteのモデルを使用する場合、AndroidStudioの機能でモデルを取り込んでおくと取り込んだモデルの使用Sampleコードを見ることができます。 モデル取り込み時に表示された詳細部分の下部の方に記載があり、閉じてしまっても再度モデルをダブルクリックすることで見ることができます。 モデルは取り込んだモジュールのsrd->main(ここは取り込み時の設定で変わる)->mlフォルダに入っています。 今回使用したモデルのSampleコードは下記のようです。 sample.kt val model = LiteModelSsdMobilenetV11Metadata2.newInstance(context) // Creates inputs for reference. val image = TensorImage.fromBitmap(bitmap) // Runs model inference and gets result. val outputs = model.process(image) val detectionResult = outputs.detectionResultList.get(0) // Gets result from DetectionResult. val location = detectionResult.locationAsRectF; val category = detectionResult.categoryAsString; val score = detectionResult.scoreAsFloat; // Releases model resources if no longer used. model.close() これを参考に実際のコードを作ります。 MainActivity.kt private fun analyze(image: Image) { var model: LiteModelSsdMobilenetV11Metadata2? = null try { val bitmap = toBitmap(image) model = LiteModelSsdMobilenetV11Metadata2.newInstance(applicationContext) val tensorImage = TensorImage.fromBitmap(bitmap) val outputs = model.process(tensorImage) val list = outputs.detectionResultList list.filter { it.scoreAsFloat > 0.5f }.map { // ここに判別結果が流れてくる } } catch (e: Exception) { } finally { model?.close() model = null } } あとはこのanalyzeメソッドをカメラのデータ取得部につなげ、カメラから流れてきたImageデータを入れてやると完成です。 モデルから出てきたデータに対してフィルターを掛けているのは、スコア(解析結果の信用度)が低いものを弾くためです。これを入れておかないと人のいない部屋で何故か人がいることになってしまったりします。 実機動作 適当に呼び出しボタンと結果表示用TextViewだけつけたアプリで試しましたが、カメラ映像を表示することなくカメラからの画像データを使えています。 ちなみに、カメラ使用時はAndroid12では下図のように右上にカメラ使用中マークが出るのでユーザーに知られずにということは無理です。 まとめ CameraX APIのImageAnalysis.Analyzerを使いましょう。 個人的にはこういう場合にAIというワードを使うのは嫌いなのですが、わかりやすさのためにAIとします。 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む