- 投稿日:2019-04-15T22:40:48+09:00
VisualStudioでNativeActivityを使ってAPKを作ってみる - ver.01 assetsフォルダからファイルを読む
はじめに
今回はassetsフォルダからファイルを読み込むところを作ろうと思います。
前回の開発環境をそのまま使用します。前回のリンク
ソリューションの構成
大きく分けて2つのプロジェクトで構成されています。
AndroidApplecation.NativeActivity
- ダイナミックライブラリ(soファイル)を生成するためのプロジェクト。
- 主要なプログラムコードはこちらに配置します。
AndroidApplecation.Packaging
- APK内に含めるファイルを配置するプロジェクト。
- アセット用のフォルダはこちらに配置します。
アセットフォルダの準備
早速アセット配置用のフォルダを作成していきます。
1. 「ソリューション エクスプローラー」->「AndroidApplecation.Packaging」を右クリックし、「追加(D)」->「新しいフォルダー(D)」を選択します。
作成した「assets」フォルダで右クリックし、「エクスプローラーでフォルダーを開く(X)」を選択し、今回テストで使用する「testlist.txt」を配置して下さい。
「testlist.txt」の中身は下記のようにして下さい。
textlist.txtabcdefghijklmnopqrstuvwxyz
プロジェクトにtestlist.txtを追加します。Visual Studioに戻り、「ソリューション エクスプローラー」->「すべてのファイルを表示」を選択します。
「AndroidApplecation.Packaging」->「assets」->「testlist.txt」を右クリックし、「プロジェクトに含める(J)」を選択します。
「AndroidApplecation.Packaging」->「assets」以下に「testlist.txt」が追加されていることを確認します。
これでassetsフォルダの準備は完了です。
C++言語の設定
今回の開発ではC++11を使用したいと考えています。
そのためC++11を使用するための設定を行います。
「ソリューション エクスプローラー」->「AndroidApplecation.NativeActivity」を右クリックし、「プロパティ(R)」を選択します。
「AndroidApplecation.NativeActivity プロパティページ」というウィンドウが立ち上がります。
「構成(C)」を「すべての構成」に変更し、「プラットフォーム(P)」を「すべてのプラットフォーム」に変更します。
その状態で「構成プロパティ」->「C/C++」->「言語」内の「C++ 言語標準」という項目を「C++11 (-std=c++11)」に変更します。
これでプログラムを組む準備ができました。
テキストを読み込む関数を実装
それでは早速「testlist.txt」を読み込んでみようと思います。
「ソリューション エクスプローラー」->「AndroidApplecation.Packaging」->「main.cpp」を開き、リソースを読み込む下記ソースコードを記載します。main.cpp#include <assert.h> /// <summary> /// リソースを読み込む /// </summary> /// <param name="manager">アセットマネージャー</param> /// <param name="filePath">ファイルパス</param> /// <param name="fileSize">ファイルサイズ</param> /// <returns>成功:読み込んだデータ</returns> /// <returns>失敗:nullptr</returns> void* LoadResource(AAssetManager* manager, const char* filePath, unsigned int* fileSize) { AAsset* asset = AAssetManager_open(manager, filePath, AASSET_MODE_BUFFER); assert(asset); void* data = nullptr; if (asset) { size_t size = AAsset_getLength(asset); data = malloc(size); // データを読み込む AAsset_read(asset, data, size); AAsset_close(asset); if (fileSize) { *fileSize = static_cast<unsigned int>(size); } } return data; }AndroidNDKには、AAssetManagerというassetsフォルダにアクセスするための仕組みが用意されています。
今回はこの仕組みを使ってファイルアクセスの部分を作ってきます。
簡単にそれぞれの用途を説明しますと、
- AAssetManager_open関数:ファイルを開く
- AAsset_getLength関数:ファイルサイズを取得する
- AAsset_read関数:ファイルをメモリに読み込む
- AAsset_close関数:ファイルを閉じる
となります。
logcatを表示
LoadResource関数を実際に使ってみる前に、動作確認するための準備をします。
今回は簡単に確認するためにログを出力して行こうと思いますので、「logcat」を表示していきます。
「ツール(T)」->「Android ツール」->「logcat」を選択するだけです。
これで準備完了です。LoadResource関数を使ってみる
それでは実際にLoadResource関数を使って実際にリソースを読み込んでテキストの文字列をlogcatに出力してみようと思います。
android_main関数がmain.cppにあると思いますので、そちらに記載していきます。
下記の記載を参考にソースコードを追記してみて下さい。main.cpp(一部抜粋)/** * これは、android_native_app_glue を使用しているネイティブ アプリケーション * のメイン エントリ ポイントです。それ自体のスレッドでイベント ループによって実行され、 * 入力イベントを受け取ったり他の操作を実行したりします。 */ void android_main(struct android_app* state) { /* 省略 */ // ループはスタッフによる開始を待っています。 // 動作チェック before unsigned int fileSize = 0; void* fileData = LoadResource(state->activity->assetManager, "textlist.txt", &fileSize); if (fileData) { char textStr[fileSize + 1]; strncpy(textStr, (const char*)fileData, fileSize); textStr[fileSize] = '\0'; LOGI("%s", textStr); } free(fileData); // 動作チェック after while (1) { /* 省略 */ } }これであとは実行するだけです。
結果
logcat上にtestlist.txtに記載されている内容が表示されたでしょうか?
表示されていればファイル読み込みが正常に実装できたことになります。
まとめ
これでassetsフォルダ上のファイルにアクセスできるようになりました。
次回はlibpngを使って何かしら絵を表示する仕組みを実装していければと思っています。
- 投稿日:2019-04-15T18:48:38+09:00
Android エミュレータ (AVD) で hosts による名前解決をさせるメモ
AVD にぱっと DNS で名前解決できない開発用とかのサーバーへの名前解決をさせるためのメモ。
まず方法としましては以下がぱっと浮かびます:
- ローカルに Proxy サーバーを立ててそこを経由する
- Chrome の Developer Tools の Remote Devices からポートフォワードする
/etc/hosts
を設定する。(1) ですが。まず、頻繁に変えるなら Proxy サーバーを立てて設定しておくと、変更時の反映が楽そうです。
(2) について。Chrome には Developer Tools にポートフォワード機能があり、
AVD 側のlocalhost
の任意のポートを、
ホスト側からアクセスできる任意のポートにポートフォワードしてつなげることができます。なので、この例では
localhost:9999
はdev.api.org:80
につながるようになります。ただ仮想ホストへのアクセスの場合は、
Host
ヘッダーを自分で指定する必要があります。
(もしコードに変更を加えられるのであれば、Retrofit2 のInterceptor
でヘッダーを指定するとかできますが、ちょっとめんどうですね)。(3) の
/etc/hosts/
は、ホストと IP の対応を手軽に自分のマシン内で名前解決するのに便利ですね。今回はこれを使います:まず AVD を書き込み可能にする
${SDK_PATH}/emulator/emulator -writable-system -avd "${AVD_NAME}" &
SDK_PATH
は Android SDK ホームへのパス。
mac だったら${HOME}/Library/Android/sdk/
とかですね。
AVD_NAME
は起動したい AVD の名前です。
スペースは_
に置き換えます。
(例:Pixel 2 XL API 28
→Pixel_2_XL_API_28
)これで AVD が書き込み可能で起動します。
(Play Store が有効だと無理っぽいです)。ホストの
hosts
を AVD に push するcd ${PLATFORM_TOOLS} ./adb root ./adb remount ./adb pull /system/etc/hosts /tmp cat /etc/hosts >> /tmp/hosts ./adb push /tmp/hosts /system/etc/hostsで、今起動中の AVD に対して
adb
経由でhosts
をpush
します。
(PLATFORM_TOOLS
は${HOME}/Library/Android/sdk/platform-tools
とかです)これで
hosts
での名前解決できるようになりました。
- 投稿日:2019-04-15T17:51:37+09:00
java kotlin IntとIntの除算(割り算)にご注意
なんでこんな簡単なことにハマったのでしょう?
私と同じようにハマって時間を無駄にする方がいないように備忘録下記は当然の如く0.25と出ると思っていましたが...
var rate: Double = 0.0 rate = 1 / 4 Log.v("TEST:", "rate:${rate}")下記のようなコンパイルエラーがでる。
Type mismatch: inferred type is Int but Double was expectedgoogle翻訳様:「型が一致しません:推定型はIntですがDoubleが必要です」
そんなことわかっておるワイ!!!
ん? あっ Σ(゚д゚;) ,,,, そういう事か。
IntとIntの計算なので計算結果の型の判定がIntになっていたんですね...
俺よ、なぜ気づかなかった。。。ということで解決策。どっちか、もしくは両方をDoubleに合わせてやればよい。
val num1 = 1.toDouble() val num2 = 4.toDouble() val aaa = num1 / num2 Log.v("TEST:", "rate = ${aaa}")V/TEST:: rate = 0.25はい。想定どおりの結果が返ってきました。
自分の頭の悪さに涙が止まらんです。補足
ちなみに...
val aaa = (1/4).toDouble() Log.v("TEST:", "rate = ${aaa}")V/TEST:: rate = 0.0こうすると 計算結果がIntで来てそれをDoubleに変換しているみたいになるから
想定する結果が返ってきません。
10 / 4
とかだと2.0
になるから注意。では、よい kotlin 生活を!
- 投稿日:2019-04-15T16:42:00+09:00
BottomSheetDialogFragmentで全画面表示だけ有効にしたい
目的
BottomSheetDialogFragmentで全画面表示だけ有効にしたい
コード
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog dialog.setOnShowListener { dialog -> val d = dialog as BottomSheetDialog val bottomSheet = d.findViewById(com.google.android.material.R.id.design_bottom_sheet) as FrameLayout? val behavior = BottomSheetBehavior.from(bottomSheet) behavior.state = BottomSheetBehavior.STATE_COLLAPSED behavior.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { override fun onSlide(bottomSheet: View, slideOffset: Float) { //何もしない } override fun onStateChanged(bottomSheet: View, newState: Int) { //この条件分岐追加しないと画面が消えた後モーダルの半透明黒マスクだけが残る if (newState == BottomSheetBehavior.STATE_HIDDEN) { dismiss() behavior.state = BottomSheetBehavior.STATE_COLLAPSED } //途中で止まろうとするので強制的に全画面表示する else if (newState == BottomSheetBehavior.STATE_COLLAPSED) { behavior.state = BottomSheetBehavior.STATE_EXPANDED } } }) //下から出てきて全画面表示されるようにする behavior.state = BottomSheetBehavior.STATE_EXPANDED }
- 投稿日:2019-04-15T16:27:50+09:00
Androidのビルド時にファイル更新が反映されない時、キャッシュをクリアする方法
./gradlew clean cleanBuildCache
- 投稿日:2019-04-15T14:58:54+09:00
Flutterウィークリー #54
Flutterウィークリーとは?
FlutterファンによるFlutterファンのためのニュースレター
https://flutterweekly.net/この記事は#54の日本語訳です
https://mailchi.mp/flutterweekly/flutter-weekly-54※Google翻訳を使って自動翻訳を行っています。翻訳に問題がある箇所を発見しましたら編集リクエストを送っていただければ幸いです。
読み物&チュートリアル
2019年のFlutterの最初のユーザー調査からの洞察
https://medium.com/flutter-io/insights-from-flutters-first-user-survey-of-2019-3659b02303a5
Flutter UXリサーチチームによるQ1ユーザー調査に関するFlutter使用に関する新しいレポート。なぜそしてどのように私はFlutterを学んでいますか?
https://medium.com/flutter-community/why-and-how-am-i-learning-flutter-2652c15c8113
Wilton RibeiroはFlutterに関する彼の学びの道と彼がそれを学び始めた理由を共有します。Flutterコーディングインタビューをクラックする:Call Centerを設計する
Dmytro Gladkyiは、 Flutterを使用して典型的なコールセンターのインタビューテストを解決します。WidgetGigs - Flutterジョブボード
Flutter関連の仕事のための新しい求人掲示板。履歴書をアップグレードしましょう。Reduxを使ってFlutterでアニメーションを作成する方法
https://medium.com/flutter-community/how-to-create-animations-in-flutter-with-redux-e04ec70afbc9
Paulina Szklarskaが、アプリでReduxを使用しながらアニメーションを処理する方法を説明します。Flutter :ゴールデンテスト - ウィジェットとスナップショットの比較
ゴールデンテストは、 Flutterテストシステムではあまり知られていない機能の1つです。カタリーナシェレメットはそれらをマスターする方法を紹介します。Flutter不変ビジネスロジック
David Leybovichが、 Reduxビジネスロジックにおける不変性について説明します。Flutter :クイズゲームの作り方
https://medium.com/flutter-community/flutter-how-to-build-a-quiz-game-596d0f369575
Flutterクイズゲームを作成するためのFrancesco Mineoによる完全なチュートリアル。FlutterアニメーションI:背景色の変化
https://medium.com/flutter-community/flutter-animation-i-background-color-transition-39dcbada7335
Divyanshu Bhargavaが、トゥイーンアニメーションを使用してアプリの背景色を変更する方法を説明します。Flutterエラーメッセージが改善されました
https://medium.com/@eibaan_54644/better-errors-messages-for-flutter-a21c53982a99
Amigaシステムを覚えていますか? Stefan Matthias AustがFlutterの古い "達人瞑想"エラーメッセージを再現します。Flutter UIをフェードインする
https://medium.com/@felixblaschke/fade-in-your-uis-in-flutter-c81b1c345f70
Felix Blaschkeは、自分のライブラリsimple_animationsを使用して画面内の要素をフェードインさせます。Flutterレイアウトの基本
https://medium.com/@seenickcode/the-basics-of-flutter-layout-88339a4d2cd2
基本に立ち返って。 Nick ManningがFlutterレイアウトを紹介します。InheritedWidgetを使用したFlutterでの「依存性注入」
FlutterよるFlutter依存関係を注入するための賢い方法Flutter派手な背景アニメーション
https://medium.com/@felixblaschke/fancy-background-animations-in-flutter-4163d50f5c37
Flutter :ネットワーク要求(HTTP)
https://medium.com/@lawrey/flutter-network-request-http-6ae5667fff73
Lawrence TanがFlutter httpリクエストを行うための完全な紹介をします。Flutterビデオプレーヤー - Chewie Tutorial
https://resocoder.com/2019/04/13/flutter-video-player-chewie-tutorial/
より良いビデオ処理のためのChewieライブラリでビデオプレーヤーを作成することに関するチュートリアル。Flutter - MobXによる状態管理
https://diveintoflutter.blogspot.com/2019/04/flutter-state-management-with-mobx.html
ビデオ&メディア
6分でFlutterナビゲーション - ナビゲータのみを使用
https://www.youtube.com/watch?v=DlArCl8jvlo&feature=youtu.be
この短いフラッターチュートリアルでは、ナビゲーションを含む現実世界のシナリオについて説明します。Flutterチュートリアル-とFirestore Flutter
https://www.youtube.com/watch?v=R12ks4yDpMM
FlutterアプリケーションにFirebaseを統合する方法についてのビデオ。Flutterテキスト、フォントおよびThemeData
https://www.youtube.com/watch?v=ePLhVrT4au0
TextTheme、カスタムフォント、およびTextStyleを使った基本的なマテリアルデザインテーマを使用してテキストをスタイルする方法を学びます。Flutter :sqlite(sqflite)| CRUD操作
https://www.youtube.com/watch?v=9D1VX6uGylU&feature=youtu.be
Flutterデータベースを処理するためのsqfliteライブラリの使用法の紹介。FlutterとGoogle Mapsを使ってモバイルアプリを構築する(Cloud Next '19)
https://www.youtube.com/watch?v=RpQLFAFqMlw
Brett MorganとMatthew Sullivanによる、Cloud Next '19イベントのFlutter Mapsの使用に関する講演。フラッターアニメーションを使用してボタンを上下にアニメートする
https://www.youtube.com/watch?v=d-yx0F2FoaA&feature=youtu.be
このチュートリアルでは、クリックしたときにボタンを上下に移動させるためのアニメーションの作成方法を説明します。ライブラリ&コード
flutter_movie_ui
https://github.com/sergiandreplace/flutter_movie_ui
先週の土曜日、私は上にあったFlutterでUIの作成について話チューリッヒミートFlutter 。ここにはソースコード(便利なステップバイステップのコミット)とプレゼンテーションへのリンクがあります。
ジデグル/素材について
https://github.com/JideGuru/material-about
モバイルアプリで使用する画面について。
olexale / arkit_flutter_plugin
https://github.com/olexale/arkit_flutter_plugin
ARKit Flutterプラグイン
luigi-rosso / sequenced_loader
https://github.com/luigi-rosso/sequenced_loader
Flareコントローラを使用してFlutterローディングアニメーションを駆動する方法の例。
nonybrighto / flutter_firebase_tic_tac_toe
https://github.com/nonybrighto/flutter_firebase_tic_tac_toe
バックエンドとしてflutterとfirebaseを使って作られたシンプルなマルチレイヤ三目並べアプリケーション
- 投稿日:2019-04-15T12:28:24+09:00
ローカル実行でAndroidアプリの課金をテストする
debug
証明書を使用したビルドでは課金のテストはできませんが、release
証明書を使用すればAndroid Studioのローカル実行で課金をテストすることができます。
Google Play アプリ署名を有効にしている場合でも、アップロード証明書で署名すれば課金をテストできます。以下にGUIを使用した手順を紹介します。
File -> Project Structure -> appモジュール -> signing でアップロード証明書の情報を入力する
Build Typesタブに移動し、Signing Configに↑で作成したものを設定する
必要に応じてdebuggable
をtrue
に設定する。
もちろんreleaseビルドの証明書の設定などは
build.gradle
を手動で修正しても構いません。
- 投稿日:2019-04-15T00:20:58+09:00
[Android]ShareCompatを使ってシェア(共有)する場合の画像の渡し方、コールバックの受け取り方
↓これの事
わりとたくさん情報がありそうな気がしたが、意外と出てこなかったので、メモ書き。
ライブラリ
- com.android.support:support-compat:28.0.0
実装
SomeActivity.java// アクティビティ内から実行する前提のコード private void showShareChooser() { File tempFile = new File(getApplicationContext().getExternalCacheDir(), tempImgFilePath); // ファイルをシェアするためにURIを取得する場合は、FileProviderを通じて、後述するオーソリティの名前を指定して取得する必要がある Uri uri = FileProvider.getUriForFile(getApplicationContext() , getApplicationContext().getPackageName() + ".provider" , tempFile); ShareCompat.IntentBuilder builder = ShareCompat.IntentBuilder.from(this); builder.setChooserTitle(chooserTitle) // シェアする時のタイトル .setSubject(subject) // 件名。使われ方はシェアされた側のアプリによる .setText(text) // 本文。使われ方はシェアされた側のアプリによる .setStream(uri) // ファイルをシェアする時は、そのURIを指定 .setType("image/jpeg"); // ストリームで指定したファイルのMIMEタイプ // URIに対する読み取り権限を付与する Intent intent = builder.createChooserIntent().addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // コールバックを受け取りたい場合は、そのインテントを使ってアクティビティを開始する if (intent.resolveActivity(getPackageManager()) != null) { startActivityForResult(intent, SNS_SHARE); } // 結果を受け取らなくても良い場合は、ビルダーからそのまま開始できる // builder.startChooser(); }戻りを受け取る場合は、 通常どおり
onActivityResult
で受け取れる。@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case SNS_SHARE: // 戻りを受け取って何らか処理する // resultCode は必ずゼロになるので、 RESULT_OK で判定しない doSomething(); break; default: super.onActivityResult(requestCode, resultCode, data); break; } }ファイルを共有する場合
画像などを共有する場合は、Bitmapをそのまま共有したりできないため、一旦ファイルに保存する必要がある。
また、以下のように保存先からの読み出しを許可する必要がある。まず、パスをXMLで指定する。
src/main/res/xml/provider_paths.xml<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-cache-path name="cache" path="." /> </paths>
external-cache-path
などは保存先に応じて変わる。
英語だけどFileProviderの公式リファレンスを参照。
次に、そのプロバイダをAndroidManifest.xml
で指定する。AndroidManifest.xml<manifest package="com.example" xmlns:android="http://schemas.android.com/apk/res/android"> : <provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/> </provider> : </application> : </manifest>参考