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

RxjavaとRetrofitで非同期通信を行う

Androidで非同期通信を使おうとして、AsyncTaskLoaderを使うと、コードが長くなり、考慮する点も多いので、Rxhjavaを使ってみました。
今ではこちらの方が主流な理由がわかりました。

①ライブラリの追加

下記ライブラリを追加しました。

build.gradle
    implementation 'com.squareup.retrofit2:retrofit:2.6.0'
    implementation 'io.reactivex.rxjava2:rxjava:2.2.9'
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
    implementation 'com.squareup.retrofit2:converter-simplexml:2.3.0'
    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'

rxJavaのAndroid版のrxAndroidも導入しています。

②Retrofitの実装

今回はxmlをparseする処理を行うので、Retrofitを使います。
タグの名前を指定すれば、値が取得できるので、便利です。
まずは、interfaceの作成です。

interface RssClient {

    @GET("{rssPath}")
    fun get(@Path("rssPath") path: String) : Observable<BlogEntity>
}

Rxjavaで使うため、戻り値をObservable型にしています。
また、@Path("rssPath")で実際に使用するときに引数を使うことで、カスタマイズできます。
その時に"{rssPath}"が同じ値になります。
なので、動的にURLを作成したいときに使えます。

次にEntityを作成します。

Entityについては下記の記事を参照してください!
Retrofitでxmlの値を取得する

ここまででRetrofitを使えるようになりました。

③Rxjavaの実装

最後に、Rxjavaを使って、非同期処理を行います。
手順としてはRetrofitを作成し、対象のURLで通信を行い、取得したデータを使って、その後処理を行うという流れです。

MainActivity.kt
val retrofit = Retrofit.Builder()
                       .baseUrl(https://×××××××××××/)
                       .client(client)
                       .addConverterFactory(SimpleXmlConverterFactory.create())
                       .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                       .build()

                    val response = retrofit.create(RssClient::class.java).get("rss")

                    // 非同期で記事を取得し、メインスレッドでその後の処理を行う
                    response.observeOn(AndroidSchedulers.mainThread())
                            .subscribeOn(Schedulers.newThread())
                            .subscribe( {
                                //UIの更新など取得したデータを使って処理を行う
                            }, {
                                Log.e("ERROR", it.cause.toString())
                            })

.addConverterFactory(SimpleXmlConverterFactory.create())でxmlをパースすることを定義し、.addCallAdapterFactory(RxJava2CallAdapterFactory.create())でRetrofitの処理結果を、RxJava2が利用できる形にしています。
そして、interfaceで定義したget()を実行します。
1点注意しないといけないのが、baseURLは末尾に/がないとエラーが発生します。

.subscribeOn(Schedulers.newThread())で新しい別スレッドで実行することを定義し、observeOn(AndroidSchedulers.mainThread())で取得結果をメインスレッドで受け取るようにしています。subscribeの前半の{}は成功したときの処理、こうはんはエラーが発生したときの処理になっています。AsyncTaskLoaderを継承させてみたいなややこしい処理はいらず、エラー処理も単純なので、記述も減ります。

最後に使ってみて見やすくて、便利でした。また、処理のチェーンなども手軽にできそうで何より、コード量が減るのがいいですね。

参照

Connect to an API With Retrofit, RxJava 2, and Kotlin
Android working with Retrofit and RxJava in Kotlin

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

キラッとプリ☆チャンのコーデ管理アプリを作ってみた話

前置き

Qiitaで記事投稿やってみた!という気持ちで大変恐縮ではあります。


本題

職業訓練校で学んだ程度ではあるのだが、Androidのアプリを作ることはできる。
下記の書籍を参考にしながら、タイトルのアプリを簡単ではあるけど、作った。

基礎&応用力をしっかり育成! Androidアプリ開発の教科書 なんちゃって開発者にならないための実践ハンズオン

とあるフォロワーの要望からすべてが始まった

勉強も兼ねて、先ほど紹介した書籍のサンプルプログラムをサクサクっと作った。
「勉強するわけだから、自分でも楽しく作れるものを作りたいな」という気持ちが出てくる。
最初は、アイカツ!キャラクターのような喋り口で、お天気予報とか、マストドンのインスタンス「キラキラッター」にアクセスするような、簡単なアプリを作ろうとしていた。

…で、言ってみた。すると。

ちゃんぷりのコーデ管理アプリ作って定期的にメンテしてくれたらたぶん首位いくレベルでDLされるよ?

とか言われちゃったので、本気にした。

どう作ったの、おじさん?

コーデ保存ってことは、SharedPreferenceかSQLite?
と思ったので、まずは書籍のサンプルプログラムでSQLiteを軽く理解して制作を始めようと思った。

イメージ画像としてはこんな感じ。メモ書きなので見づらいのはご容赦。
メモ書き。画像大きくてすまんやで…
実際は、画像内の「それか、こうか」以下の実装になりましたとさ。おわり。

ソースコード

なにかの参考になればと思ったので、一部抜粋なテイで載せてみた。

    // ListViewオブジェクトを取得
    ListView lvPrichan = findViewById(R.id.lv_prichan);

    // リストビューに表示するプリチャン稼働弾のリストオブジェクトを作成
    List<String> prichanCorde = new ArrayList<>();

    // リストデータの登録。プリチャン稼働弾が増えたとしても
    // 簡単に追記できるようにした
    prichanCorde.add("キラッとプリ☆チャン ジュエル1弾");
    prichanCorde.add("キラッとプリ☆チャン ジュエル2弾");
    prichanCorde.add("キラッとプリ☆チャン ジュエル3弾");

    // アダプターオブジェクトを作成
    ArrayAdapter<String> adapter = new ArrayAdapter<>(MainActivity.this,
            android.R.layout.simple_list_item_1,prichanCorde);
    lvPrichan.setAdapter(adapter);
    lvPrichan.setOnItemClickListener(new ListItemClickListener());
}

private class ListItemClickListener implements AdapterView.OnItemClickListener {

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        switch (position) {
            case 0:
                // ジュエル1弾のコーデリスト
                Intent priJ1intent = new Intent(MainActivity.this,PrichanJewel1.class);
                startActivity(priJ1intent);
                break;
            case 1:
                // ジュエル2弾のコーデリスト
                Intent priJ2intent = new Intent(MainActivity.this,PrichanJewel2.class);
                startActivity(priJ2intent);
                break;
            case 2:
                // ジュエル3弾のコーデリスト
                Toast.makeText(MainActivity.this,"まだないよ",Toast.LENGTH_SHORT).show();
                break;

上記はメイン画面処理。コーデ管理画面の処理は下記。

// 選択されたコーデの主キーIDを表すフィールド
int _prichanId = -1;
// 選択されたコーデ名を表すフィールド
String _prichanCordeName = "";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_prichan_jewel1);
    // リストビューを取得
    ListView lvJprichan = findViewById(R.id.lv_J1prichan);
    // リスナーを登録
    lvJprichan.setOnItemClickListener(new ListItemClickListener());
    // 長押しリスナーを登録
    lvJprichan.setOnItemLongClickListener(new ListItemLongClickListener());
}

private class ListItemClickListener implements AdapterView.OnItemClickListener {

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        // タップされた行番号をフィールドの主キーIDに代入
        _prichanId = position;
        // タップされた行のデータを取得してフィールドに代入
        _prichanCordeName = (String) parent.getItemAtPosition(position);
        // データベースヘルパーオブジェクトを作成
        J1DatabaseHelper helper = new J1DatabaseHelper(PrichanJewel1.this);
        // データベース接続オブジェクトを作成
        SQLiteDatabase db = helper.getWritableDatabase();

        String cordeGet = "";
        try {
            String sql = "select * from J1prichancorde where _id = " + _prichanId;
            Cursor cursor = db.rawQuery(sql, null);
            if (cursor.moveToNext()) {
                int idxCorde = cursor.getColumnIndex("cordeget");
                cordeGet = cursor.getString(idxCorde);
            }
        }
        finally {
            db.close();
        }
        if (cordeGet.equals("true")) {
            // 所持データを保持されたことを表示
            Toast.makeText(PrichanJewel1.this,
                    "持っているコーデカードだよ。",
                    Toast.LENGTH_SHORT).show();
        }
        else {
            Toast.makeText(PrichanJewel1.this,
                    "持っていないコーデカードだよ。",
                    Toast.LENGTH_SHORT).show();
        }
    }
}

private class ListItemLongClickListener implements AdapterView.OnItemLongClickListener {

    @Override
    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {

            // タップされた行番号をフィールドの主キーIDに代入
            _prichanId = position;
            // タップされた行のデータを取得してフィールドに代入
            _prichanCordeName = (String) parent.getItemAtPosition(position);
            // データベースヘルパーオブジェクトを作成
            J1DatabaseHelper helper = new J1DatabaseHelper(PrichanJewel1.this);
            // データベース接続オブジェクトを作成
            SQLiteDatabase db = helper.getWritableDatabase();
            try {
                // インサート文を用意
                String sqlInsert = "insert into J1prichancorde (_id, name, cordeget) values (?,?,?)";
                // SQL文字列を元にプリペアードステートメントを取得
                SQLiteStatement stmt = db.compileStatement(sqlInsert);
                // 変数のバインド
                stmt.bindLong(1, _prichanId);
                stmt.bindString(2, _prichanCordeName);
                stmt.bindString(3,"true");
                stmt.executeInsert();
            }
            finally {
                // データベースを閉じる
                db.close();
            }
            Toast.makeText(PrichanJewel1.this,
                    "登録完了!",Toast.LENGTH_SHORT).show();
        }
        // 通常のクリックイベントを発生させない
        return true;

最初、これで無事動くじゃろ~~~
と思ってたおじさんが馬鹿だった。

Insert処理の問題で、アプリが落ちるという出来事が起きた。

            // タップされた行番号をフィールドの主キーIDに代入
            _prichanId = position;
            // タップされた行のデータを取得してフィールドに代入
            _prichanCordeName = (String) parent.getItemAtPosition(position);
            // データベースヘルパーオブジェクトを作成
            J1DatabaseHelper checkhelper = new J1DatabaseHelper(PrichanJewel1.this);
            // データベース接続オブジェクトを作成
            SQLiteDatabase checkdb = checkhelper.getWritableDatabase();
            String cordeGet = "";
            try {
                String sql = "select * from J1prichancorde where _id = " + _prichanId;
                Cursor cursor = checkdb.rawQuery(sql, null);
                if (cursor.moveToNext()) {
                    int idxCorde = cursor.getColumnIndex("cordeget");
                    cordeGet = cursor.getString(idxCorde);
                }
            }
            finally {
                checkdb.close();
            }
            if (cordeGet.equals("true")) {
                Toast.makeText(PrichanJewel1.this,"既に登録しているから、登録できないよ!",
                        Toast.LENGTH_SHORT).show();
            }

既にInsertでデータベースに挿入してて、長押ししてしまった時とかあるじゃろ?
そういう時に
「既に入ってるからInsertはさせんよ。じゃあの。(エラーで終了)」
となるので、こうした。

ここまで作るのにおじさんは一日かかりました。

で、使ってもらった。

十分管理できる!
と嬉しい言葉をいただきましたァん♪
また、こんな言葉も頂いた。

リストでチェックマーク選べて最終確定できて中で保持できてたらそれだけでも違う!

この実装に関しては、調査が必要だが、できないことでもないだろう。と思っているので
やってみようと思う。

以上です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Android 広告IDの取り扱い方

広告ID - Play Console ヘルプより
https://support.google.com/googleplay/android-developer/answer/6048248?hl=ja

広告 ID は、ユーザーがリセットできる広告用の固有の ID で、Google Play 開発者サービスから提供されるものです。この広告 ID によってユーザーの管理性は向上し、デベロッパーはシンプルな標準システムで引き続きアプリを収益化できます。また、ユーザーは ID をリセットしたり、Google Play アプリ内のパーソナライズド広告(以前のインタレスト ベース広告)をオプトアウトしたりできます。

広告IDとは

  • ユーザーを識別するためのID

広告の配信や、ユーザーの分析に使用します。

広告IDの特徴

  • ユーザーが任意のタイミングでリセットできる
  • ユーザーがオプトアウトすることができる
オプトアウトとは

個人情報の第三者提供に関し、個人データの第三者への提供を本人の求めに応じて停止すること。

ユーザーが広告のカスタマイズをオプトアウトしている場合は、
以下の目的で、広告IDを使用してはいけない。

  • 広告目的のプロフィール構築
  • パートナライズド広告のターゲット設定
オプトアウト設定方法

設定アプリ > Google > 広告 > 広告のカスタマイズをオプトアウトする
※Android 5.2以下ではGoogle設定アプリから設定

広告IDの使用規約

Android 広告IDの使用より
https://play.google.com/intl/ja_ALL/about/monetization-ads/ads/ad-id/

広告IDを使用するためには規約があります。

広告ID使用上の注意点

  • 広告とユーザーの分析以外で使用してはいけない。
  • 広告IDの収集と使用、規約への遵守について、ユーザーに開示する必要がある。
  • ユーザーのオプトアウト設定を遵守する必要がある。

ユーザーがオプトアウト設定している場合

  • 広告目的でユーザーのプロフィールを作成したり、ユーザーをパーソナライズド広告のターゲットに設定したりするために広告IDを使用してはいけない。
  • ただし、コンテンツ ターゲット広告、フリークエンシー キャップ、コンバージョン トラッキング、レポート、セキュリティや不正行為の検出などに使用することはできる。

ユーザーの同意なしにしてはいけないこと

  • 個人を特定できる情報や、永続的なデバイス ID(SSAID、MAC アドレス、IMEI など)に関連付けたりしてはいけない。
  • 新しい広告IDを、以前の広告IDや以前の広告IDからのデータに紐づけてはいけない。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Koin2.0でお手軽DI(Android)

この記事ではAndroidでのKoinの使い方を扱います。

Koinとは

KoinとはKotlin用のDependency injection Framework (依存性注入フレームワーク)です。

AndroidでDI FrameworkといえばDaggerやKodeinなどもありますが、Koinは
- Kotlin100%で書かれていること
- シンプルな使い方
が特徴です。

めっちゃシンプルです。
AAC ViewModelが秒でInjectionできます。
簡単すぎる!!!!!!!!!!!!!!!!幸せ❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣ ってなる。

この記事ではバージョン2.0.1を用いています。

DIとは

DIとはDependency injectionの略で日本語で依存性注入と言います。
詳しくは、こちらの記事 (猿でも分かる! Dependency Injection: 依存性の注入)
などがわかりやすく解説してくれてるので見てください。

実際に使う

物は試し、まずは触ってみましょう。

アプリに導入する

以下をbuild.gradle(app)dependenciesに追加してください。

build.gradle(app)
def koin_version = "2.0.1"
implementation "org.koin:koin-core:$koin_version"
implementation "org.koin:koin-core-ext:$koin_version"
implementation "org.koin:koin-android:$koin_version"
implementation "org.koin:koin-android-scope:$koin_version"
implementation "org.koin:koin-android-viewmodel:$koin_version"
implementation "org.koin:koin-android-ext:$koin_version"

syncして完了です。

実装

今回はViewModeに依存するFragmentを例に進めていきます。

class MainFragment : Fragment() {
    // ここにViewModelを持ちたい。
}

class MainViewModel : ViewModel() {
    /* functions */
}

moduleを用意し、koinをスタートさせる 

Applicationクラスを継承したクラスで、
injectしたいクラスらを記述したmoduleを用意しstartKoinメソッドを呼ぶとKoinをスタートさせることができます。
moduleにinjectしたいクラスを記述する際には、

Singletonにしたい場合 single{}
AAC ViewModelを使う場合 viewModel{}
その他 factory{}

今回はAAC ViewModelをinjectするので、viewModel{}を用います。

App.kt
class App : Application() {
    override fun onCreate() {
        startKoin{
            androidContext(applicationContext)
            modules(module)
        }
    }

    val module = module {
        viewModel { MainViewModel()}
    }
}

injectする

あとはinjectしたい場所でinjectするだけです。

変数に対してby inject()をしてあげることでinjectすることができます。
ViewModelをinjectする際はby viewModel()を用います。

今回は、例に沿ってMainFragmentMainViewModelをinjectします。
ですのでby viewModel()を用います。

MainFragment.kt
class MainFragment : Fragment() {

    val viewModel by ViewModel()

    //...
}

これでinjectできました!!!!!!!!!!!!!!!!!!!!!!!!
簡単すぎる!!!!!!!!!!!!!!!!幸せ❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣

ViewModelがRepositoryを持つ場合

MainViewModelが引数にRepositoryを持つ場合も試してみましょう。

class Repository(){
   //get~~() etc...
}

class MainViewModel(val repository : Repository) {
    //...
}

まず、先程のApp.ktmoduleの中に引数にinjectしたいRepositoryを記述します。
今回RepositoryはSingletonであってほしいので、single{}メソッドを用います。

引数にinjectするにはget()メソッドを呼ぶと勝手に必要なものを引数にinjectしてくれます。

App.kt
class App : Application() {
    override fun onCreate() {
        startKoin{
            androidContext(applicationContext)
            modules(module)
        }
    }

    val module = module {
        single { Repository()}
        viewModel { MainViewModel(get())} // add
    }
}

簡単すぎる!!!!!!!!!!!!!!!!幸せ❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣

まとめ

少ない記述で済ませられるので、小規模なアプリこそKoinを用いるのが良いと思います。
Koin使うと幸せ❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣❣ って感じですね!!!!!

間違い等ありましたらコメント下さい...申し訳ありません

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Android開発時にR.*が全部無効になった場合

レイアウトXMLの確認とかClean ProjectとかInvalidate Cacheとか一通り試して駄目だった場合

import android.R

が何かの拍子で追加されて邪魔してる場合があるので、コレを消す

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React Native製Androidアプリでコマンドラインビルドすると画像が表示されないことがある

--assets-dest android/app/src/main/resreact-native bundle のオプションに付与する。

すると画像リソースとしてresディレクトリ以下に配置されるようになる。
でもこれを付与しなくても動くときもあるのが謎。。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Flutter実行環境の構築(Android StudioとXcode)

概要

急遽Flutterの検証を行う必要があったので備忘録兼ねて構築からインストールまでを記事にまとめたいと思います。
iOSでの実行も確認したいので、Xcodeでの実行もまとめていますが、メインはAndroid Studioでの環境構築となります。

各種手順

Android Studioと各種ツールのインストール
Xcodeインストール
Flutterインストール
Android Studioに対するFlutterプラグインのインストール
Flutterプロジェクト作成
Flutterの各種初期設定(初回のみ)
Flutterアプリケーション起動確認

Android Studio

インストールまで

Android Studio公式に接続して「Download Android Studio」をクリック

AndroidStudioダウンロード_Mac_01

利用規約の「同意します」にチェックを入れダウンロード
下記のファイルがダウンロードされるので実行

Windows:android-studio-ide-183.5522156-windows
Mac:android-studio-ide-183.5522156-mac.dmg

Windowsの場合
ダウンロードされたexeファイルを実行して「Next」をクリック
install_Windows_01.png

「Next」をクリック
install_Windows_02.png

「Next」をクリック
install_Windows_03.png

「Install」をクリック
install_Windows_04.png

完了したら「Next」をクリック
install_Windows_05.png

Macの場合
上記のファイルを実行して生成される「Android Studio.app」をアプリケーションフォルダに入れた後appを実行する

初期設定

インストールが完了したAndroid Studioを起動する

「Do not import settings」にチェックがついた状態で「OK」をクリック
AndroidStudioダウンロード_Mac_02

「Don't send」をクリック
AndroidStudioダウンロード_Mac_03

「Next」をクリック
AndroidStudioダウンロード_Mac_04

「Custom」にチェックが入っていることを確認して「Next」をクリック
「Standard」の場合、テーマ選択以降は省略される
AndroidStudioダウンロード_Mac_05

好きな方のテーマを洗濯して「Next」をクリック
AndroidStudioダウンロード_Mac_06

※「Custom」の場合表示
インストールするコンポーネントとAndroid SDKのインストール先を指定して「Next」をクリック

Android SDKのインストール先を変更した場合
Flutterはデフォルトインストール先を基にしてAndroid SDKを確認するので、変更した場合は
環境変数ANDROID_HOMEを作成し、パスはAndroid SDK Locationを指定すること
Android_install_ex1.png

※「Custom」の場合表示
「Next」をクリック
Android_install_ex2

インストール構成を確認して「Finish」をクリック
AndroidStudioダウンロード_Mac_07

「Finish」をクリック
AndroidStudioダウンロード_Mac_08

HAXMのインストールに失敗した場合

HAXM installation failedと表示された場合

HAXM公式サイトに接続後、「Downloads」欄のhereをクリック
HAXM_install_01.png

対応するOSのzipをダウンロード
HAXM_install_02.png

zipを解凍後にできたアプリケーションを実行
「続ける」をクリック
Windows: intelhaxm-android.exe
Mac: IntelHAXM_7.5.1.dmg
HAXM_install_03.png

インストール先の変更が必要でなければ「インストール」をクリック
HAXM_install_04.png

インストール後に下記の図のメッセージが表示される場合は機能拡張を許可する必要がある
HAXM_install_05.png

「システム環境設定」の「セキュリティとプライバシー」を開き、ダウンロードしたアプリケーションの実行許可下部にIntel HAXMへの権限を確認する文章が追加されているので「許可」をクリック
HAXM_install_06.png

実行確認

Macの場合
MacでAndroidエミュレータが起動しない(HAXMが起動しない)とき
kextstat | grep intelを実行した場合に何らかの文字列が出力されたらインストールが完了している

HAXMのアンインストール

HAXMで何らかの不具合が発生している場合は一旦アンインストールしてインストールをし直した方が良い

Windowsの場合
Intel Hardware Accelerated Execution Manager(HAXM) インストールとアンインストール
【インストール先もしくはダウンロードしたファイル先】/silent_install.bat -uを実行する

Macの場合
sudo 【インストール先もしくはインストール時にダウンロードしたファイル先】/silent_install.sh -uを実行する

Android Studioの日本語化

Android Studio / IntelliJ IDEA の日本語化と設定
MacでAndroid Studioを日本語化する

Pleiades プラグインに接続して使用しているOSのプラグインをダウンロード
language_change_01.png

ダウンロードされたzipファイルを解凍後、以下のアプリケーションを起動
Mac: 解凍先/pleiades-mac/setup.app
language_change_02.png

「選択」をクリックして先ほどインストールした「【インストール先】/Android Studio/bin/studio64.exe」もしくは「Android Studio.app」をクリックして「開く」を選択
language_change_03.png

設定に問題がないことを確認して「日本語化」をクリック
language_change_04.png

Android Studioを起動して日本語化されていることを確認する

AVDの作成

今回は仮想デバイスを作成したいだけなのでHAXMを使用した高速AVDでの構築を行なっておりません。
高速AVDで仮想デバイスを構築したい場合は下記の記事がとても参考になります。
Windowsで高速AVDを利用するまでの手順をものすごく詳しく解説

「ツール」、「AVDマネージャー」をクリックしてAndroid仮想デバイス・マネージャーを起動後、「仮想デバイスの作成」をクリック
AVD_create_01.png

任意のハードウェアを選択して「次へ」をクリック
AVD_create_02.png

既にシステムイメージのダウンロードが完了している場合は選択するだけで良いが、目的のイメージがインストールされていない場合は
「Download」をクリックし、ダウンロードが完了したら再度選択をして「次へ」をクリックする
AVD_create_03.png

構成を変更する場合は各種変更後、「完了」をクリック
AVD_create_04.png

シミュレータの起動

「ツール」、「AVDマネージャー」をクリックして作成したデバイスの右側にある「▶︎」をクリック
simulator_Android_01.png

ばらくするとOSが起動するので動作を確認し、正常に動くことを確認する
simulator_Android_02.png

完全アンインストール

こちらの記事を書いている最中、Android Studioを壊してしまったので完全アンインストール方法を探していたのですが
Windows、Mac共に削除だけだと消えないそうなのでまとめました。
再インストール前に全ての環境を初期化したい場合は下記を実行すれば全削除を行うことができます。

Windowsの場合

Android studioを完全にアンインストールしたい。

下記フォルダを削除すれば設定を削除して初期化を行う事が可能

# Android SDKのインストール先を変更している場合、下記フォルダではなくANDROID_HOMEのパスを確認する
C:/Users/【ユーザ名】/AppData/Local/Android/sdk
# .AndroidStudioX.Xはバージョン番号によってフォルダ名が異なる
C:/Users/【ユーザ名】/.AndroidStudioX.X
C:/Users/【ユーザ名】/.gradle

Macの場合

MacでAndroidStudioを完全アンインストール

Android SDKを削除する場合のコマンドはrm -r ~/Library/Android*だが、インストール先を変更している場合はANDROID_HOMEのパスを確認すること

Xcode

インストールまで

App Storeを起動してXcodeで検索して「インストール」をクリック
Xcode_install_01.png

インストールが完了後、初めて起動する場合はライセンス規約が出るので「Agree」をクリック
Xcode_install_02.png

シミュレータの起動

Xcodeでの起動

「Xcode」、「Open Developer Tool」、「Simulator」をクリック
simulator_iOS_01.png

しばらくするとOSが起動するので動作を確認し、正常に動くことを確認する
simulator_iOS_02.png

Android Studioでの起動

※Flutterの各種設定が終了後に実行可能
画面右上のデバイス表示部分をクリック後、「Open iOS Simulator」をクリック
しばらくするとXcodeでの起動と同じく、エミュレータが起動する
simulator_iOS_AndroidStudio_01.png

Flutterインストール

SDKインストール

Flutter公式にアクセスして「Get started」をクリック
Flutter_SDK_install_01.png

対応するOSの部分をクリックして以下のファイルをダウンロード
Windows: flutter_windows_v1.5.4-hotfix.2-stable.zip
Mac: flutter_macos_v1.5.4-hotfix.2-stable.zip
Flutter_SDK_install_02.png

Windowsの場合
ダウンロード後に解凍して任意のフォルダに入れる
今回はC:/develop配下に格納した

格納後、環境変数PathC:/develop/flutter/binを追加する

Macの場合
ダウンロード後に解凍して任意のフォルダに入れる
今回は/Users/ユーザフォルダ/develop配下に格納した

格納後、パスを通すために.bash_profileを編集してパスを追加する

# vimで.bash_profileを編集する
vim ~/.bash_profile

# 実行直後にiキーを押して挿入モードに移行後、以下の行を追加
# 追加後にEscキーを押してノーマルモードに戻った後、:wqで保存してvimを終了させる
export PATH="$HOME/develop/flutter/bin:$PATH"

完了後、.bash_profileを再読み込みする

source ~/.bash_profile

実行確認

完了したら正常にパスが通っていることを確認する

flutter --version

# パスが通っていたら以下のような出力が行われる
Flutter 1.5.4-hotfix.2 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 7a4c33425d (9 weeks ago) • 2019-04-29 11:05:24 -0700
Engine • revision 52c7a1e849
Tools • Dart 2.3.0 (build 2.3.0-dev.0.5 a1668566e5)

  ╔════════════════════════════════════════════════════════════════════════════╗
  ║                 Welcome to Flutter! - https://flutter.dev                  ║
  ║                                                                            ║
  ║ The Flutter tool anonymously reports feature usage statistics and crash    ║
  ║ reports to Google in order to help Google contribute improvements to       ║
  ║ Flutter over time.                                                         ║
  ║                                                                            ║
  ║ Read about data we send with crash reports:                                ║
  ║ https://github.com/flutter/flutter/wiki/Flutter-CLI-crash-reporting        ║
  ║                                                                            ║
  ║ See Google's privacy policy:                                               ║
  ║ https://www.google.com/intl/en/policies/privacy/                           ║
  ║                                                                            ║
  ║ Use "flutter config --no-analytics" to disable analytics and crash         ║
  ║ reporting.                                                                 ║
  ╚════════════════════════════════════════════════════════════════════════════╝


Android Studioプラグインインストール

「ファイル」もしくは「Android Studio」から「環境設定」をクリック

「プラグイン」タブをクリック
Flutter_plugin_install_01.png

上の検索欄にFlutterを入力してEnterキーを押すとプラグイン一覧が検索されるのでFlutterをインストール
Flutter i18nは多言語対応プラグイン
Flutter_plugin_install_02.png

インストールが完了したら「Restart IDE」をクリックしてAndroid Studioを再起動
Flutter_plugin_install_03.png

Flutterプロジェクト作成

新規にプロジェクトを作成する場合

「ファイル」、「新規」、「New Flutter Project」をクリック
「Flutter Application」をクリックして「次へ」をクリック
Flutter_Project_01.png

「Flutter SDK path」で先程設定したFlutterのフォルダを指定して「次へ」をクリック
Flutter_Project_02.png

「完了」をクリック
Flutter_Project_03.png

既存のFlutterプロジェクトを開く場合

既存のプロジェクトをインポートして開いた場合、Dart SDK is not configuredと表示されることがある
この場合、FlutterとDartのSDKへのパスが設定されていないのでパスを設定する
Dart SDK is not configured横の「Open Dart settings」をクリック
クリック後、SDKのパスを設定するウィンドウが開かれるのでFlutterDartのSDKに下記を設定する
Flutter: 【インストール先】/flutter
Dart: 【インストール先】/flutter/bin/cache/dart-sdk
SDK_import_01.png

設定後、「OK」をクリックすれば環境チェックが行われる

インポート後にエラーが出る場合

'package get' has not been runと出力される

「表示」、「ツール・ウィンドウ」、「ターミナル」とクリック後に下記コマンドを実行する
※flutterコマンドが見つからないというエラーが発生する場合はFlutterの環境変数に誤りがある

flutter packages get

Waiting for another flutter command to release the startup lock...と表示されて進まない
プロセスがロックされてしまっている
flutterコマンドを打った時に"Waiting for another flutter command to release the startup lock..."が出た時の対処法

【FlutterSDKのパス】/bin/cache/lockfileを削除して再実行
※プロセスが全て終了していることを確認すること

プロジェクト起動後に実行すること(初回のみ)

flutter doctorを実行してセットアップを完了するために必要なプラットフォームの依存関係があるかどうかを確認する
基本的には下記のように、実行するべきコマンドが表示されているのでコピーして実行する

[!] Android toolchain - develop for Android devices (Android SDK version 29.0.0)
    • Android SDK at /Users/【ユーザ名】/Library/Android/sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-29, build-tools 29.0.0
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01)
    # エラー個所は✗、警告箇所は!で示される
    ! Some Android licenses not accepted.  To resolve this, run: flutter doctor --android-licenses

Xcode installation is incompleteというエラーが発生する

Xcodeをインストールしただけではコマンドラインツールのバージョンが古いままになっている
下記コマンドを実行してコマンドラインツールのバージョンを更新する

[✗] iOS toolchain - develop for iOS devices
    ✗ Xcode installation is incomplete; a full installation is necessary for iOS development.
      Download at: https://developer.apple.com/xcode/download/
      Or install Xcode via the App Store.
      Once installed, run:
        sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer

エラーを解消後、再度flutter doctorを実行して全ての項目にが付くことを確認する

アプリケーション実行

Androidでの実行

※Android Studioを実行してプロジェクトを開いていること

Androidデバイスを接続するかエミュレータを起動後、画面右上の「▶︎」をクリックしてFlutterプロジェクトを実行する
Flutter_Project_04.png

iOSでの実行

※Android Studioを実行してプロジェクトを開いていること

Android StudioでiOSのエミュレータを起動後、画面右上の「▶︎」をクリックしてFlutterプロジェクトを実行する

Flutterアップデート

Flutterのバージョンを更新したい場合は以下のコマンドを実行する

flutter upgrade

最後に

Android及びiPhoneの開発経験はあまりないので手順を忘れそうだと思いまとめました
割と突貫で書いているので誤字などあるかもしれません

参考

MacでAndroidエミュレータが起動しない(HAXMが起動しない)とき
Intel Hardware Accelerated Execution Manager(HAXM) インストールとアンインストール
Android Studio / IntelliJ IDEA の日本語化と設定
MacでAndroid Studioを日本語化する
Windowsで高速AVDを利用するまでの手順をものすごく詳しく解説
Android studioを完全にアンインストールしたい。
MacでAndroidStudioを完全アンインストール
flutterコマンドを打った時に"Waiting for another flutter command to release the startup lock..."が出た時の対処法

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

aapt.exeのエラーが出たときの備忘

androidアプリをビルドしていたら、見慣れないエラーが出た。

Process 'command 'C:\Users\XXXXXXXXXX\AppData\Local\Android\Sdk\build-tools\24.0.2\aapt.exe'' finished with non-zero exit value 1

aapt.exeを実行したときの終了コードが0じゃないってことは分かったけど、じゃぁどこでエラーになっているのか探してみても、これ以上のログは出ていない。

Gradleをインストールする

調べてみたところ、Gradleなるものを使えば詳細なログが出るらしい。
(Gradleとは、Groovyで記述するビルド自動化システム)
ということで、以下を参考にしてGradleのインストールをしてみた。

参考にした記事:
【Java】Gradleのインストールと基本的な使い方(画像付きで解説)

インストールできているか確認する。

C:\Users\XXXXXXXX>gradle -v

 ------------------------------------------------------------
Gradle 3.2.1
------------------------------------------------------------

Build time:   2016-11-22 15:19:54 UTC
Revision:     83b485b914fd4f335ad0e66af9d14aad458d2cc5

Groovy:       2.4.7
Ant:          Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM:          1.7.0_80 (Oracle Corporation 24.80-b11)
OS:           Windows 8.1 6.3 amd64

ビルドログを確認する

Gradleのインストールができたため、さっそく以下を実行してログを確認する。

C:\Users\XXXXXX\AndroidStudioProjects\DataBaseApp2>gradlew assembleDebug --info

……………

Successfully started process 'command 'C:\Users\XXXXXXX\AppData\Local\Android\Sdk\build-tools\24.0.2\aapt.exe''
C:\Users\XXXXXXX\AndroidStudioProjects\DataBaseApp2\app\src\main\res\layout\activity_main.xml:25:32-40: AAPT: String types not allowed (at 't
extColor' with value ' #F5F5F5').

C:\Users\XXXXXXX\AndroidStudioProjects\DataBaseApp2\app\build\intermediates\res\merged\debug\layout\activity_main.xml:18: error: Error: Strin
g types not allowed (at 'textColor' with value ' #F5F5F5').

カラーコードにスペース入ってる…!!!
ということで削除し再ビルドしたら解決した。

参考にした記事:
エラー Unsupported major.minor version 52.0 の対処方法

Android StudioでJavaのバージョン

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Android GestureDetectorの使い方

アンドロイドのGestureDetectorの使い方を紹介いたします

背景

ウェブビューをスワイプことによって、前のページに戻ったりしたいです

コアソースコード

MainActivity.java

public class MainActivity extends AppCompatActivity {

    WebView webView;
    private GestureDetector mGestureDetector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initializa();
    }

    private void initializa(){
        initialGesutre();
        initlaWebView();
    }

    private void initialGesutre(){
        mGestureDetector = new GestureDetector(this,mOnGestureListener);
    }

    private void initlaWebView(){
        webView = (WebView) findViewById(R.id.webView);
        webView.loadUrl("https://www.yahoo.co.jp");
        webView.getSettings().setJavaScriptEnabled(true);
        webView.setWebViewClient(new android.webkit.WebViewClient() {
            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
            }
        });

        webView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                mGestureDetector.onTouchEvent(event);
                return false;
            }
        });

    }

    private final GestureDetector.SimpleOnGestureListener mOnGestureListener = new GestureDetector.SimpleOnGestureListener(){
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

            float distance_x_vector = e2.getX() - e1.getX();
            float distance_x = Math.abs(e2.getX() - e1.getX());
            float distance_y = Math.abs(e2.getY() - e1.getY());

            //ここから判断します、左スワイプしているか、右へスワイプしているか
            //判断したら、WebViewにJavascriptインジェクトします
            //webGoAndForward()
            return false;
        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return super.onSingleTapUp(e);
        }
    };

    private void webGoAndForward(Boolean forward){
        if (webView == null){
            return;
        }

        if(forward){
            webView.goForward();
        }else{
            webView.goBack();
        }
    }
}

activity_main/xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

結論

自分はネットでGestureDetectorについて色々調べて、やっと実装しました。ここでシンプルなコードを載せます。

皆に参考になれば幸いです

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Bitrise で google_services.json を扱う

毎回 google_services.json を扱うプロジェクトを Bitrise に載せる時に忘れているので記録まで。初めて扱う人の参考にもなれば。

google_services.json は一般的に .gitignore に記述して git にコミットしないので、CI で Lint を掛けるとコケます。Bitrise の場合はワークフローにファイルを生成するステップを追加できるのでそこで google_services.json を生成するようにして回避します。

  • Secrets に変数を定義して google_services.json の中身を保存します(青く記述されている部分に登録するシークレットの中身は、Expose for Pull Request を有効にしない限り安全である旨書かれています)。ここでは GOOGLE_SERVICES_JSON と云う名前の変数を定義しています。

bitrise_secret.png

  • WorkflowsAndroid Lint の前に Generate Text File のステップを追加します。File Name はプロジェクトに合わせて変更する必要があります。このプロジェクトでは app/ 以下に google_services.json を置いてあるので app/google_services.json のパスでファイルを生成します。ファイルの中身は Insert Variable で先に定義したシークレットを選択します。

bitrise_workflow.png

bitrise.yaml にもちゃんとステップが追加されています。

- generate-text-file@0.1.0:
    inputs:
    - file_content: "$GOOGLE_SERVICES_JSON"
    - file_name: app/google-services.json

これで Lint でコケることなくビルドを通すことができます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む