20200714のAndroidに関する記事は5件です。

React Native Firebase v6 + Android 8+ でプッシュ通知受信時のポップアップ表示させる

やりたいこと

React Native Firebase の Cloud Messaging を使ってプッシュ通知受信時の処理を実装。

ドキュメント通りに対応して iOS ではバックグラウンド・フォアグラウンド(※注1)とも特に問題ない。

Android でも受信するには受信するが、ポップアップ表示されない。Android 8 (Oreo) 以上では通知チャネルを明示的に指定して通知の重要度を設定しなければポップアップ表示されないので、これは当然。

通知チャネルを作成する必要があるので、やり方を調べると firebase.notifications() を使用して設定できそうな回答が見つかる。が、 React Native v6 にはこのメソッドは存在しない。どうやら v5 -> v6 で削除されたらしく、チャネルに関する設定を行う方法は v6 では提供されていない模様。React Native Firebase v5 はすでにサポート外となっているので、今更入れるのも微妙。

公式ドキュメントでは通知チャネルなどの細かい設定を行いたい場合は、同じ開発チームが作っている Notifee を使うことを推奨しているが、これは1アプリ $240 のライセンス購入が必要。

チャネル設定したいだけなのに……。

方法

しかたがないので Android でネイティブ実装してしまう。

android/app/src/〜/MainActivity.java にこんな感じでメソッド作って…

  private void createNotificationChannel() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      String id = "notification"
      CharSequence name = "お知らせ";
      String description = "新しいメッセージの受信などをお知らせするよ";
      int importance = NotificationManager.IMPORTANCE_HIGH;
      NotificationChannel channel = new NotificationChannel(id, name, importance);
      channel.setDescription(description);
      NotificationManager notificationManager = getSystemService(NotificationManager.class);
      notificationManager.createNotificationChannel(channel);
    }
  }

で、 onCreate() の一番下あたりに createNotificationChannel(); と書いて呼び出す。

あとは React Native プロジェクトルートの firebase.json にデフォルトのチャネルを追加。


{
  "react-native": {
    ...
    "messaging_android_notification_channel_id": "notification"
  }
}

id, name, description は適当に変えてください。

脚注

※注1: フォアグラウンド時には messaging().onMessage イベントにより任意の処理を実行できるが、 OS ネイティブ UI の通知として表示するには別途対応が必要)

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

android studioのデバッグで値を監視する

android studioというかintellijというかデバッグもろもろ
最近知って便利なので備忘録
※AndroidStudio3.2

とりあえずやる

debugでプロジェクトを起動する
debugウィンドウの眼鏡みたいなアイコンをクリックしてwatchesウィンドウを表示する
debugウィンドウが表示されてない場合は「View」→「Tool Windows」→「debug」をクリックして表示する
無題.png

watchesウィンドウの緑色のプラスボタンをクリックして確認したい値を入力する
あとは適当に確認したいタイミングにブレイクポイント貼っとくとその時の中身が見れる
無題.png

ブレイクポイントで止めてる途中に追加しても見れるしViewの状態も見れるしでいい感じ
無題.png

ほかにも便利な機能をうまく使っていきたいなぁ

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

政府の接触確認アプリ(COCOA)の機能を補完するアプリを作ってみた(3密チェッカー)

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409628/33a241c4-5ff6-b793-6e7c-c4c05d52debf.png

はじめに

私は、ラビットプログラムの名前でAndroidスマートフォン向けアプリを開発・公開している19歳の学生です。
去年スマホアプリ開発コンテスト アプリ甲子園 2019に「ピックアップ通知音」アプリを応募して、特別企業賞 マイナビ賞を受賞しました。
https://www.applikoshien.jp/report/2019.html
あれから半年ほど経って最近これといったものを作っていなかったのですが、今COVID-19が流行っているので何かこれを題材にした新しいアプリが作れないかと考えていました。

その間に、5月あたりから報道されていた「接触確認アプリ」(COCOA)が公開されて実際に使ってみたのですが、何か味気ないというか、物足りないと感じたので、足りないと感じた部分を補完するアプリを自分で作ってみました。

そしてQiitaの接触確認アプリ関連の記事が話題になっていたので、私も負けずに書いてみました:grin:
https://qiita.com/Anharu/items/c00e882d678538be0ab0

なぜ1から作ったのか

COCOAはオープンソースなので、誰でも開発に参加することができます。
ですが、COCOAはできるだけ多くの国民の方に使ってもらえるようにと考えられて作られたものなので、できること・取得する情報が制限されています。
実際には個人情報を取得しないアプリなのに問題視されることが多いので、下手に機能を増やすだけだとかえって利用者数が減ってしまう恐れがあります。
そこで、COCOAとは別にアプリを作ることで、もっと多くの情報を得たいと思う人だけが使えるものになったらいいと思い、この考えに至りました。

また、COCOAはみんながインストールしていないと機能しませんが、このアプリは自分だけインストールすればすべての機能が使えるところにとてもこだわりました!
相手の判別はビーコンではなくMACアドレスで行うので、相手はBluetoothがオンの状態であるだけでOKなんです:ok_hand:

開発環境について

私はいつもと同じくAndroid Studioを使ってJavaで作りました。
COCOAはXamarinで作られているようですが、1からアプリを作れるほどの技術がなかったです...
本当はiOS版も作りたかったのですが、同じ理由で現在はAndroidのみです。
また、とにかく早く作り上げたかったので、特別難しいことはしていません。
COCOAではAppleとGoogleが共同で開発したAPI「Exposure Notification」を使用してメイン機能を実装していますが、このアプリはこのAPIは一切使用していません。
というか、個人がこのAPIを自由に使用することはできないようになっています。


ここからは、私が作ったアプリの機能と実装にあたって工夫した点を、少しコードを交えながらご紹介します。
できるだけ分かりやすくするために画像も付けたので、一緒にご覧ください!
:point_right: このアプリはGoogle Playに公開しているものです。もしよろしければダウンロードして使ってみてください!
:iphone: https://play.google.com/store/apps/details?id=rabbitp.check.threec

ホームタブ

アプリを起動してまず表示される画面です。
この画面では、今日と昨日の合計すれちがい・密接人数と、バックグラウンドの動作状態を確認することができます。
バックグラウンド状態のところには、次の測定時間と最後に測定したときの3密状態が表示されます。
また、「今すぐ3密状態をチェック」ボタンをタップすると、次回測定時間まで待たなくてもすぐに調べることもできます。
https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409628/f7b8c336-9833-42a5-6484-065380b496bb.png
今すぐ3密状態をチェックするを押して測定した様子はこちらです。
https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409628/7747ee84-6a48-3651-e290-7bb435a57f07.png

今すぐ3密状態をチェックするときのプログラムと、バックグラウンドで測定するときのプログラムは、時間を指定して自動実行するかどうかの違いだけであとはほとんど同じです。

測定する項目について

15分おきの自動測定や、「今すぐ3密チェック」ボタンを押したときは次の項目を測定しています。

:convenience_store: 密閉 → マイクで騒音レベルを調べる

騒音レベルが40dBを超えた場合、密閉と判定します。

:family: 密集 → Bluetoothデバイス数を調べる

デバイス数が40台を超えた場合、密集と判定します。

:two_men_holding_hands: 密接 → 近接Bluetoothデバイス

RSSI(電波強度)が-55以上のデバイス数が3台を超えた場合、密接と判定します。

:satellite_orbital: 位置情報 → GPSで緯度と経度を調べる

自動測定時のみ、測定場所を記録しておきます。
「危険度分布マップ」機能は、この情報をもとに地図上にピンを立てます。

:abc: BluetoothデバイスのMACアドレス

MACアドレスを調べることで既に検出済みデバイスかどうかの判定ができるので、同じデバイスをカウントしないようにするために記録しておきます。
この記録は1日ごとにリセットされます。

Exposure Notification APIは使えない

本日より、Exposure Notification の提供を開始します。
同技術は公衆衛生機関が利用でき、Android 及び iOS 搭載端末上で動作します。

引用元:https://japan.googleblog.com/2020/05/apple-google-exposure-notification-api-launches.html

COCOAアプリは、接触者検知や通知といった処理をExposure Notification APIに任せています。
COVID-19に感染した人の濃厚接触者を追跡するために開発されたこのAPIは、利用範囲が公的機関に限定されているため個人利用ができません。
そのため、3密の測定をするには他の方法で行わなければいけません...
IMAGE ALT TEXT HERE
APIについての参考動画(日本語訳):https://www.youtube.com/watch?v=jRIOwmywuQE

Exposure Notificationを使用しない測定方法について

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409628/be8171d6-213b-3a6b-9b67-bcd4ebcb4dd8.png
※画像は「接触確認アプリ及び関連システム仕様書」の文章の一部
やりたいことは、周りのデバイス数とCOCOAをインストールしている人数の測定です。
仕様書を見る限りこのAPIを使わないとバックグラウンドではBluetooth(BLE)検索ができないと思われがちですが......

問題1:BLEとバックグラウンドの相性

実際試してみると、普通にBluetoothもBLEもバックグラウンドで検索できることが分かりました!(あっさり解決!!!)
なので、APIを使わなくてもBluetooth検索をしてデバイス数をカウントすれば密集人数を調べられます。
また、RSSI(電波強度)を調べれば近くにあるかどうかもわかるので、密接人数も調べることができます。
Serviceを継承したクラスに検索処理を書き、ActivityからstartForegroundService(APIレベル26未満の場合はstartService)を呼べば実行できます。
※startForegroundServiceの場合は、開始から5秒以内にstartForegroundをServiceクラス内で呼ぶ必要があります。→詳しくはこちら

問題2:UUID取得できない、startScan勝手に終わらない!

先に結論を言うと、私はgetBluetoothLeScannerとstartScanを組み合わせて測定する方法で実装しました。
なぜ両方を使う必要があるのか... まずはこの表を見てください。

①BroadcastReceiverクラスを作ってstartDiscovery ②ScanCallbackクラスを作ってstartScan
バックグラウンド動作 ○ できる ○ できる
画面オフ時の動作 ○ できる △ 検索対象のUUIDを制限する必要がある
デバイス検索終了判断 ○ できる × 手動で止めないといけない
COCOA判別(UUID取得) × できない ○できる

①:https://www.hiramine.com/programming/bluetoothcommunicator/02_scan_device.html
②:https://www.hiramine.com/programming/blecommunicator/02_scan_device.html
それぞれ試してみて分かったことを表にまとめました。

①は画面オフ時でもバックグラウンド同様動作しますが、②はそのままやっても画面オフ時だけ動作しません。
これはAndroid8.1(APIレベル27)から仕様が変更になったことが原因だそうです。(参考サイト1参考サイト2
このページに書かれているように検索するUUIDを制限すれば、問題なく動作します。

①でデバイス検索が終了したとき、1度BroadcastReceiverが呼ばれるので、そこでintent.getAction()がBluetoothAdapter.ACTION_DISCOVERY_FINISHEDになったら終了したと分かりますが、②は見つけるたびにScanCallbackが呼ばれ続けるので終了判断ができません。(終わらせるためには時間指定などで手動で止める必要があります。)

①ではUUIDの取得ができません。(これについては詳しく分かってないです...参考サイトはここ?
②を使えば、UUIDを取得することができます。(詳しくはこちら

こうなるととても厄介です。
①だと対象がExposure Notificationかどうか判別できないし、②だと検索がひと段落した時に停止させることができません。
ならどうすればいいか、両方使えばいいんです!
①で密集・密接を調べるためのデバイス数測定を行い、②でCOCOAインストール人数を測定します。
また、周囲のExposure Notificationの信号の数は大体4秒で取得できることも分かりました。(Beacon Scopeというアプリで事前に調べました。)
つまり、②は検索開始から4秒経ったら止めるようにします。

周囲のデバイス数を測定するためのプログラム

startDiscoveryでBLE検索を開始し、変化があったらBroadcastReceiverが呼ばれます。

    ...省略

    //ブロードキャストレシーバーの登録
    context.registerReceiver(mBroadcastReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
    context.registerReceiver(mBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED));

    //Bluetoothアダプタの取得
    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    scanner = mBluetoothAdapter.getBluetoothLeScanner();

    //スキャン開始
    mBluetoothAdapter.startDiscovery();

    ...省略

    //ブロードキャストレシーバー
    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver()
    {
        @Override
        public void onReceive(Context context, Intent intent )
        {
            String action = intent.getAction();

            if( BluetoothDevice.ACTION_FOUND.equals( action ) )
            {
                //発見!!!
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                String addmacaddress=device.getAddress();  //デバイスのMACアドレス
                int rssi=intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);  //デバイスの電波強度

                ...省略

                return;
            }

            //Bluetooth端末検索終了
            if( BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals( action ) )
            {
                try {
                    //スキャンの停止
                    mBluetoothAdapter.cancelDiscovery();

                    //ブロードキャストレシーバーの登録解除
                    context.unregisterReceiver(mBroadcastReceiver);


                    //次にCOCOAのインストール数を調べる
                    startScanBLE(context);

                }catch (Exception e){

                }

                return;
            }
        }
    };

COCOAのインストールデバイス数を測定するためのプログラム

startScanでBLE検索を開始し、変化があったらScanCallbackが呼ばれます。

    //Exposure NotificationのUUID
    String ExpNoti_UUID = "0000fd6f-0000-1000-8000-00805f9b34fb";
    //スキャン時間
    private static final long SCAN_PERIOD = 40000;
    //BLE機器のスキャンを行うクラス
    private BluetoothAdapter mBluetoothAdapter;
    //BLE機器のスキャンを別スレッドで実行するためのHandler
    private Handler mHandler;

    //デバイススキャンコールバック
    private static ScanCallback mLeScanCallback = new ScanCallback()
    {
        //スキャンに成功
        @Override
        public void onScanResult(int callbackType, ScanResult result)
        {
            BluetoothDevice device = result.getDevice();
            String MACaddress=device.getAddress();  //デバイスのMACアドレス
            int rssi=result.getRssi();  //デバイスの電波強度
            List<ParcelUuid> uuids = result.getScanRecord().getServiceUuids();

            if (uuids != null) {
                for (ParcelUuid uuid : uuids) {
                    //発見!!!(指定したUUIDの場合のみ)

                    ...省略

                }
            }


        }

        // スキャンに失敗
        @Override
        public void onScanFailed( int errorCode )
        {
            super.onScanFailed( errorCode );
        }
    };

    ...省略

    //スキャン開始(COCOAのインストール数を調べる)
    private void startScanBLE(Context context)
    {
        //Exposure NotificationのUUIDのみ調べる
        ScanSettings settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
        ScanFilter uuidFilter = new ScanFilter.Builder().setServiceUuid(new ParcelUuid(UUID.fromString(ExpNoti_UUID))).build();
        List<ScanFilter> scanFilters = new ArrayList<>();
        scanFilters.add(uuidFilter);

        //スキャン開始
        scanner.startScan(scanFilters, settings, mLeScanCallback);

        //指定した時間で検索終了
        mHandler = new Handler();
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //指定時間が経過したらScanCallbackを止める
                stopScanBLE(context);

                ...省略

            }
        }, SCAN_PERIOD);

    }

    ...省略

    //BLEスキャンの停止
    public static void stopScanBLE(Context context)
    {
        //一定期間後にスキャン停止するためのHandlerのRunnableの削除
        mHandler.removeCallbacksAndMessages( null );

        //BluetoothLeScannerの取得
        android.bluetooth.le.BluetoothLeScanner scanner = mBluetoothAdapter.getBluetoothLeScanner();
        if( null == scanner )
        {
            return;
        }
        scanner.stopScan( mLeScanCallback );
    }

長くなりましたが、これが測定のメインプログラムです。

詳細情報タブ

Spinner項目1:「蓄積データからの種類別グラフ」

測定データをもとに様々なグラフが表示されます。
上の2つは、3密の割合を示す円グラフです。
1つ目が今日の3密割合、2つ目が最大21日分の測定データから計算した3密割合です。
https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409628/97b4729e-5a7c-b369-dbb7-ade88cb6cab7.png

下にスクロールすると、更に2つグラフが表示されます。

  • 「これまでの日別危険度」では、1日ごとに1密を1カウントとして全体の50%(毎時4回測定*24時間*3密*0.5=144カウント)を危険度100%として密割合を日別に表示しています。
  • 「1日の時間別割合」では、1時間ごとに3つ(密閉・密集・密接)の測定結果を足して、どの時間帯が危険だったかをぱっと見て分かるようにグラフ化しています。(そのまま足して一番値が大きいものを基準に表示しているので、単位はありません。)

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409628/4e1aa19f-16cb-f74d-4179-ada49f819c96.png

グラフの描画には、「MPAndroidChart」を使用しました。
https://github.com/PhilJay/MPAndroidChart
このライブラリ、とても便利でカスタマイズも容易なので、どんなグラフでも作れます!
データ自体は配列でセットするだけなのでとても分かりやすいです。
これは、「これまでの日別危険度」で表示しているように折れ線グラフを表示する例です。

build.gradle(appレベル)
...省略

dependencies {

    ...省略

    implementation 'com.github.PhilJay:MPAndroidChart:v2.2.5'
}

レイアウト
<com.github.mikephil.charting.charts.LineChart
    android:id="@+id/LineChart_21days"
    android:layout_width="match_parent"
    android:layout_height="200dp" />
プログラム
    LineChart LineChart_21days;

    ...省略

    LineChart_21days=view.findViewById(R.id.LineChart_21days);

    LineChart_21days.setNoDataText("グラフを描画しています...");
    LineChart_21days.setDescription("最大21日分の測定データから生成");
    LineChart_21days.setHighlightPerTapEnabled(false);  //タップしてハイライトを無効化
    LineChart_21days.getLegend().setEnabled(false);  //チャートラベル説明(左下のやつ)を非表示
    LineChart_21days.setScaleEnabled(false);  //ピンチイン・ダブルタップ拡大を無効化
    LineChart_21days.setDrawGridBackground(false);
    Legend legend3 = LineChart_21days.getLegend();
    legend3.setPosition(Legend.LegendPosition.BELOW_CHART_LEFT);

    //グラフに表示するデータの設定
    List<Entry> entries = new ArrayList<>();
    entries.add(new Entry("データ1", 0));
    entries.add(new Entry("データ2", 1));
    entries.add(new Entry("データ3", 2));

    LineDataSet lineDataSet = new LineDataSet(entries,"ラベル");
    lineDataSet.setDrawValues(true);
    lineDataSet.setColor(Color.parseColor("#FF5722"));  //折れ線の色
    lineDataSet.setLineWidth(2);
    lineDataSet.setDrawFilled(true);  //塗りつぶす
    lineDataSet.setFillAlpha(10);  //塗りつぶしの透明度
    lineDataSet.setFillColor(Color.parseColor("#FF5722"));  //塗りつぶしの色
    lineDataSet.setCircleColor(Color.parseColor("#FF5722"));  //外心の円の色
    lineDataSet.setCircleRadius(5);  //中心の円の半径
    lineDataSet.setCircleHoleRadius(3);  //外心の円の半径
    lineDataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);  //なめらかな折れ線

    LineData lineData1 = new LineData(labels, lineDataSet);
    lineData1.setValueFormatter(new PercentFormatter());
    lineData1.setValueTextSize(17f);
    lineData1.setValueTextColor(Color.TRANSPARENT);

    LineChart_21days.animateXY(1000, 1000);  //表示アニメーション
    LineChart_21days.setData(lineData1);

Spinner項目2:「蓄積データからの危険度分布マップ」

自動測定したデータで1密以上だった場所にはマーカー(ピン)を立ててお知らせします。
マーカーは密状態を判別できるように色を変えています。
000188.png
https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409628/7ef39698-0ab3-53c1-a55f-71a832ab2c37.png

マーカーをタップすると、いつの結果か等その時の測定データの詳細を確認することができます。
infowindow_R.png

この機能はGoogle Maps Android APIを使用して実装しています。
導入方法:https://qiita.com/yuishihara/items/8955582de6fa639eb504
マーカーをタップしたときに表示されるウィンドウを設定する:https://qiita.com/sho-h-ei/items/a40f813a5178e716fb8c

Spinner項目3:「過去20日分の詳細データ」

名前の通り、すべての測定結果を一覧で見ることができます。
2つ目のSpinnerで確認したい日付を選ぶと、上から順に0:00~23:45までの結果が書かれたCardViewが並びます。
ここには、測定時にGPSで取得した位置情報(緯度・経度)をもとに住所を市区町村名まで表示します。
何密かによって背景色を変えることで、見やすいように工夫しました。
card.png
https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409628/78e85799-c5e8-b6d0-1119-ffdd90ef4b54.png

また、CardViewをタップするとその測定場所をGoogleマップで開くようにしました。
GoogleマップのURLに緯度と経度を入れるだけで簡単に表示できます。
https://www.google.com/maps?q={緯度},{経度}
例えば、名古屋駅を開くリンクはこう書きます:https://www.google.com/maps?q=35.171131,136.881499

共有タブ

まだ未完成です!!
https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409628/a7a607af-8ca0-8382-6710-30d12431e937.png

最新情報タブ

一番上には、毎日17時くらいに更新される東京都の最新情報を、公式サイトから取得して表示しています。
取得に使用しているサイト:https://stopcovid19.metro.tokyo.lg.jp/
本当はJSON形式かCSV形式のデータを使いたいんですが、一部の情報はCSVで公開されているのですが、新規感染者数や前日比が載っていないので仕方なくホームページのHTMLを解析して取得するようにしました。
https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409628/19272e42-faab-2a2c-b8b5-eeeaa25476e2.png
その下には、JSONで取得した都道府県別の新規感染者数をグラフ化して表示しています。
ただ、こちらは更新が遅いので数日前のものです。
データ取得に使用しているサイト(esriジャパン 新型コロナウイルス対応支援サイト):https://is.gd/Aj5sjK
https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409628/c4fb9870-ad2b-c1fb-b52a-bece5fb1095a.png

ここまでが、アプリに今搭載している機能のすべてです。


Google Playで公開しています!

ぜひダウンロードして使ってみてください!!(紹介したすべての機能が使えます。)
レビューをいただけると幸いです:relaxed:
https://play.google.com/store/apps/details?id=rabbitp.check.threec
https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409628/2fe97a7c-e5e7-1006-17e3-82b635dc175e.png
Google Play および Google Play ロゴは、Google LLC の商標です。

今後の改善点

  • 「過去20日分の詳細データ」のスクロールが遅いので直す
  • もうちょっと見た目をよくする
  • 共有タブを完成させる
  • COCOAをインストールしている端末は、15分おきにBluetoothのMACアドレスが変化し続けるので、何度もカウントしないようにする対策が必要

参考サイト

:disappointed_relieved: 本文中にもし間違いがあればご教授ください。よろしくお願いします。

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

Androidアプリ開発の第一歩 AndroidStudioでアプリ実行

前回のインストール編に続き、今回は実行編です。

開発環境

  • OS:Windows 10 Home 64bit(バージョン1903)
  • 開発ソフト:Android Studio 14.0
  • 開発言語:Kotlin

Android Studioの起動

[Windowsキー]を押し、「and」→[Enter]とすると楽に起動できます。
image.png

いざプログラミング!

  1. 初めて起動した場合、このような画面が出ます。[Start a new Android project]をクリックします。
    image.png

  2. 初めのテンプレートが表示されます。結構初めから用意してくれてるのですね、便利!
    とりあえず今はEmpty Activityで。
    image.png

  3. アプリケーションの設定をします。
    image.png
    Name : 任意のアプリ名を入れます。今回は[MyFirstApp]としました。
    Package Name : Nameの名前が自動で入力されます。基本変更する必要はないでしょう。
    Service Location : 開発コードが保存される場所です。こちらも自動で指定されるので、このままで大丈夫です。
    Language : 開発言語です。Kotlinを選びます。これ、Javaもここで選択できるのですね。Javaの開発環境(JDK)が入ってなくても使えるのでしょうか??
    Minimum SDK : どのバージョンまでのAndroidをサポートするかです。幅広く利用してもらうアプリであればAndroid 4.0を選ぶのが無難ですが、おそらく使えるコードに制限がかかると思われます。私の所有スマホはPixel 3a(Android 10)ですので、まぁ二世代前のAndroid 8.0くらいにしておきます。
    Use legacy android.support libraries : こちらも古いスマホの互換性を保つかどうか。最新のAPIやSDKも試していきたいので、OFFにします。

  4. 出てきました!はじめ必要なモジュールを自動で入れてくれるため、少し時間がかかります。細かいことは後々確認していこうと思いますが、初めに表示されるファイルを2つ紹介。
    MainActivity.kt : app>java>[パッケージ名]にあります。こちらにソースコードを入れていく形になります。
    activity_main.xml : 画面のレイアウトを入れるファイルになります。
    右上にCode、Split、Designとありますが、Splitを選ぶとCodeとDesignを両方見ることができます。
    例えばデザインのHello Worldをクリックすると、どこのコードかをハイライトで示してくれます。
    image.png

  5. 少し変えてみましょう。まずHello Worldを上に持っていきます。デザイン画面のHello Worldを上にドラッグするだけです。コードが勝手に変わってくれます。
    image.png

  6. コードの12行目にあるHello World!をこんにちは!に変えると、デザインも変わります。
    image.png

いざ実行!とその前に

右上のスタートボタンを押すと実行できますが、初めの段階では、コードを実行するための環境(エミュレータ)がありません。(No Devices)
image.png

  1. [Open AVD Manager]を出します。
    image.png

  2. [Create Virtual Device...]をクリック。
    image.png

  3. なんでも良いとは思いますが、個人的に使ってるpixel 3aを選びました。
    image.png

Play Storeからアプリをインストールすることもできるのでしょうか。
公式サイトには以下のように記載されています。
https://developer.android.com/studio/run/managing-avds?hl=ja

[Play Store] 列に Google Play ロゴのラベルが付いているシステム イメージには、Google Play ストア アプリのほか、Google Play 開発者サービスへのアクセスが含まれており、[Extended controls] ダイアログの [Google Play] タブで、デバイス上の Google Play 開発者サービスをアップデートするのに便利なボタンが提供されます。

4.最新版の10+をDownload
image.png

5.[Accept]にして[Next]
image.png

6.容量が1.1GBあるようです。少し待ちます。
image.png

  1. [Finish]
    image.png

  2. [Download]のマークが消えていますね。[Next]をクリック。
    image.png

  3. [Finish]!
    image.png

ん?
image.png

いや、推奨と書いてあるからほっとけばいいかな。
image.png
はいダメでしたー。。。

VT-xの有効化

ここはPCによって違いますが、私のLENOVO G50での操作方法です。ご参考まで。
1.BIOSを起動します。通常はPC起動時のロゴ画面の時にF1とかF2を押すのですが、私のPC電源OFF時に電源ケーブルの隣にある●をピンなどで押すという、、、これが一番ハマった。。
00100lrPORTRAIT_00100_BURST20200714211413728_COVER.jpg

2.全然見えませんが、[BIOS Settings]を選択。
00000IMG_00000_BURST20200714211828441_COVER.jpg

3.[Configuration]タブの[Intel Virtual Technology]でEnterを押し、[Enable]にします。あとはF10キーで終了しましょう。

IMG_20200714_212006.jpg

再び実行

またAndroid Studioを起動します。前回の起動を記憶してくれているようで、そのままソースコードが開きました。
デバイスがPixel 3aになっています。スタートマークをクリックしましょう。
image.png

きました!けっこう時間かかった・・・。
image.png

そして私のPCが悲鳴を上げている。CPUもメモリもパンパンです。せめてメモリは上げようかなぁ(現在4GB)

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

androidのchromeでweb speech apiを使う

ずっと音声認識やりたくていろいろ試していました。

web speech apiの存在は知っていたけど、、javascriptが嫌だなぁと避けてましたが、、
やはり良さそうだと思ってちょっと頑張ってみました。

web_speech_api.html
<style>
    body{
        text-align: left;
                font-size:40px;
        -webkit-text-size-adjust:100%;
             }

        div.status{
        color:gray;
        font-size:30px;
        -webkit-text-size-adjust:100%;
    }

</style>


<body>

<div id="status-div" class=status></div>
<div id="result-div"></div>

</body>
<script>
  let finalTranscript = '';
function SPEECH(){
  const resultDiv = document.querySelector('#result-div');
  const statusDiv = document.querySelector('#status-div');
  SpeechRecognition = webkitSpeechRecognition || SpeechRecognition;
  let recognition = new SpeechRecognition();
  recognition.lang = 'ja-JP';
 // recognition.interimResults = true;暫定的な結果はandroidだとうまく出来ませんでした
  recognition.continuous = true;
  recognition.start();
  recognition.onaudiostart = function(){
    statusDiv.innerHTML = "STATUS>>認識中";
  };
  recognition.onaudioend = function() {
    statusDiv.innerHTML ="STATUS>>再読込完了";
        SPEECH();
  };
 recognition.onnomatch = function() {
        statusDiv.innerHTML="STATUS>>   ";
  };
  recognition.error = function() {
         statusDiv.innerHTML="エラー<br>ブラウザで更新してください";
  };
  recognition.onresult = (event) => {
    let interimTranscript = ''; //暫定的な結果はandroidだとうまく出来ませんがなんとなく残してます
    for (let i = event.resultIndex; i < event.results.length; i++) {
      let transcript = event.results[i][0].transcript;
      if (event.results[i].isFinal) {
        finalTranscript = '>'+transcript+'<br>'+finalTranscript;
      } else {
        interimTranscript = transcript;//暫定的な結果はandroidだとうまく出来ませんがなんとなく残してます
      }
    }

    resultDiv.innerHTML = finalTranscript;
  }

}
  window.onload =function(){
   SPEECH();
};
</script>

連続で認識させたかったので、音声認識の部分を丸ごと関数にして、音が途切れて音声認識が終了したらまたその関数を呼び出す
みたいな感じにしてます。(注:httpsサーバーに置かないと、呼び出しの度にマイクの使用許可を確認してきます。。)

pythonのある環境でしたら、このファイルが置いてあるディレクトリで

python3 -m http.server 8080

でローカル環境で試すこと出来ます

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