テクサポのぼやき

テクサポのぼやき

Frequently using command line for Docker

検証環境をサクッと作る用によく使うDockerコマンドの自分用メモ

Index

Search Docker images

You can search Docker images from the following URL;

Or type a command line as follows:

$ docker search [Image name]

Download a Docker Image

$ docker pull [Image name]:[version]

Install/Create and run a Docker container

$ docker container run [OPTIONS] IMAGE [COMMAND] [ARG...]

e.g)

$ docker container run -dit -v "/mnt/c/Users/testuser/Documents/Work:/windows" --name CentOS-8 centos:latest

List Docker containers you have created

  • List running containers
$ docker container ps
  • List all containers including not running
$ docker container ps -a

Start a container

$ docker start [Container name]

Login to the container shell

$ docker exec -it [Container name] /bin/bash

Stop a container

$ docker stop [Container name]

API Level 29 で生態(指紋)認証(Biometric Authentication)の画面を作ってみる

なんかアプリの起動時にポンって指紋認証の画面が出てきて、指紋認証できたら格好良いやん?IDとPassword入力でログインってなんかダサいし、そもそもAndroid Deviceってマルチユーザーで使用しないし、Web applicationのようにIDとPasswordの認証機構作るのって面倒やん?違うか?

ということでAPIいくつからから忘れましたが、いまさら調べるのも億劫なんで調べませんが、どうもGoogleさんが認証機構用の標準APIとテンプレートを作ってくれたようなので、これを利用しない手はないでしょう。

と言うても、Android Developers Guide のチュートリアルにならって作ってみただけです。
これね↓

Show a biometric authentication dialog

ちなみに、このチュートリアル日本語版だと動作させるまでにはかなりハードル高いので、英語版で読むことがお勧めです。それじゃやってみましょう。

Biometric Authentication の概要

概要として以下のことを実施する必要があります。

  1. DeviceのBiometric機能を利用するため、AndroidManifestにuser permission宣言の追加
  2. Biometricのライブラリを利用するため、gradleにライブラリを追加
  3. DeviceのハードウェアにBiometric機能が付いているか、指紋が登録済みかなどのチェック
  4. 指紋認証画面の表示

こんだけ。ちょー簡単なのでやってみましょう!

1. DeviceのBiometric機能を利用するため、AndroidManifestにuser permission宣言の追加

Device上の機能を使うためにマニフェストファイルに、Biometoricのpermissionを宣言しておきましょう。

app/src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
...
    //USE_BIOMETRICのPermissionを追加!
    <uses-permission android:name="android.permission.USE_BIOMETRIC"/> 

    <application
        android:allowBackup="true"
...
    </application>

</manifest>

2. Biometricのライブラリを利用するため、gradleにライブラリを追加

チュートリアルBiometricandroidx.biometric:biometricのライブラリを使用するのでModuleのgradleにライブラリを追加しておきましょう。

app/build.gradle

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
...
    implementation 'androidx.biometric:biometric:1.0.1'
...

とりあえず新しめなバージョンを指定しています。個人的には直接Gradleのファイルに記述するよりGUIから検索して追加する方が、最新版のライブラリバージョンを確認できるので好きです。

  1. Move to Project Structure > Dependancies > Modules > app
  2. Click + button
  3. Select Library Dependency

f:id:techsapp:20200406234021p:plain

  1. Enter biometric at search form in Add Library Dependency
  2. Select implementation in Step 2 and click OK

f:id:techsapp:20200406234118p:plain

ここで注意ですが、API 29で使うライブラリは"androidx.biometric"です。なので、ソースコード上で利用する場合も"androidx.biometric"が利用されていることを確認してください。似たようなライブラリ名でほとんど使い方の同じライブラリがあるので、うっかり別のライブラリを使っているとBiometricManager.fromが宣言できなくてハマったりします。しかもBiometricManagerのキーワードでググるBiometricManager.fromのスタティックメソッドのない類似クラスが出てくるので尚更混乱します。API29でBiometric使うなら、'androidx.biometric`!!絶対!!

チュートリアル間違ってるやん!ってキーボードクラッシャーしそうなところで気付きました。大概は人が間違っているのではなく、99%自分がおっちょこちょいだったりするわけです(ゝω・)テヘペロぺろ

3. DeviceのハードウェアにBiometric機能が付いているか、指紋が登録済みかなどのチェック

はい、あとは簡単。 BiometricManagerを使ってハードウェアデバイスの状態と、指紋情報の登録状況を確認します。

BiometricManager.from()のスタティックメソッドにアクティビティを渡して、'BiometricManager'オブジェクトを生成します。'BiometricManager'のcanAuthenticate()では、デバイスの状況を確認し、生体認証ができるかどうかチェックしてくれます。

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

        // importしているのが違うライブラリだと、BiometricManager.fromが解決できないし、なんとなくそれっぽく使えちゃうので気付きにくい!!
        BiometricManager biometricManager = BiometricManager.from(MainActivity.this);
        switch (biometricManager.canAuthenticate()){

            //No error detected.
            case BiometricManager.BIOMETRIC_SUCCESS:
                Log.d("Biometric TAG", "App can authenticate using biometrics.");

            //There is no biometric hardware.
            case BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE:
                Log.d("Biometric TAG", "No biometric features available on this device.");

           //The hardware is unavailable.
            case BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE:
                Log.d("Biometric TAG", "Biometric features are currently unavailable.");

           //The user does not have any biometrics enrolled.
            case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED:
                Log.d("Biometric TAG", "The user hasn't associated any biometric credentials with their account.");
        }

4. 指紋認証画面の表示

BiometricPrompt指紋認証の認証画面を作っていきます。 BiometricPromptのコンストラクタにBiometricPrompt.AuthenticationCallbackのコールバック関数(Javaでもコールバック関数って言うんだっけ?)を指定して、指紋認証の成功時、失敗時などの動作を指定します。

    private Executor executor;
    private BiometricPrompt biometricPrompt;

...
        executor = ContextCompat.getMainExecutor(MainActivity.this);
        biometricPrompt = new BiometricPrompt(MainActivity.this, executor, new BiometricPrompt.AuthenticationCallback() {
            @Override
            public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
                super.onAuthenticationError(errorCode, errString);
                Toast.makeText(getApplicationContext(), "Authentication error: " + errString, Toast.LENGTH_LONG).show();
            }

            @Override
            public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
                super.onAuthenticationSucceeded(result);
                Toast.makeText(getApplicationContext(), "Authentication succeeded!", Toast.LENGTH_LONG).show();
            }

            @Override
            public void onAuthenticationFailed() {
                super.onAuthenticationFailed();
                Toast.makeText(getApplicationContext(), "Authentication failed...", Toast.LENGTH_LONG).show();
            }
        });

BiometricPrompt.PromptInfoには、指紋認証画面に表示されるタイトルなどをセットしていきます。

        private BiometricPrompt.PromptInfo promptInfo;

        promptInfo = new BiometricPrompt.PromptInfo.Builder()
                .setTitle("Biometric login for my app")
                .setSubtitle("Log in using your biometric credential")
                .setNegativeButtonText("Use account password")
                .build();

あとは、指紋認証画面を表示させたいタイミングでBiometricPrompt.authenticateをコールすれば認証画面がポンっと表示されます。

        biometricPrompt.authenticate(promptInfo);

ふーぅっ!かんたーんっ!

情報発信元の記事を読んでますか?

タイトル書いてて思ったんだけど、今時「一次ソース」って言うのかしら?相変わらず世の中のことが良く分かりません。さっきリビングで久しぶりに地上波流れてたのでちらっと見てみたら日本アカデミー賞やってましたね。知らん人ばっかり出てた。怖い。あ、柄本明の息子は知ってた。

それはさて置き、一次ソース、情報発信元の記事ってちゃんと読んでますかね。Windows ならMicrosoftの英語原文、AndroidならGoogleの英語原文、iOSならAppleの英語原文、ネットワークならIETFの原文などなど。 僕のやっているテクニカルサポートっていう職業では、製品の使い方や設定方法、、、も大事といえば大事なんですが、それプラス、どのような仕組みの上で成り立っていて、その製品がどのように実装されている/されるべきなのかというところを知っている必要があります。というのも、えてしてトラブルというものは設定ミスによるものがほとんどなのですが、いわゆるバックライン1エスカレーションされる問題は「設定は正しいのになぜか動かない」ことがままあるのです、うんこぶりぶり。

インターネットを検索すれば世の中の親切な人がBlogやQiitaなんかで丁寧にいろんな情報を分かりやすく解説してくれていて、僕なんかも良く参考に読ませてもらってて、本当記事を書いてくれるエンジニアの方々には感謝して止まないのです。ただ、前述の通りそれら記事のサマリーだとちょっと情報が足りないのです。そもそもどのような背景や思想でそのような実装になっているのかって分からないですし、他の手段や注意事項なんかも情報元の記事に書いてあったりしますからね。

例えば僕の前回のAndroidのNotificationの記事なんか、結構端折っちゃってます。本当はもっといろんなことできますし、そもそも結構他にも考えなくちゃいけないことがあったりします。あったりしますが、まずはサマリーということで記事にしているのです。

職業柄、Enterprise系のお仕事をされているエンジニアの方とお話をするんですけどね、どうもね、読んでない。もしくはどこかの2次情報を参照されたような話ぶりをされる方が多いのです。はたまた翻訳しているサイトを読まれたとか(IPAとかはメジャーなRFCは翻訳してくれてますしね)。 どこかの参考ブログを読むのは良いんです、概要を掴む意味で日本語でかつサマリーを分かりやすくまとめてくれているので、まずはそのような記事を参考に概要を把握するって意味ですごく効率的だと思いますし。ただですね、それで全て分かった気になってませんかとね、僕はね、言いたい。

やはり、前述のとおり誰かが書いてくれた記事って掻い摘んで書いてあるんですよ。その人の主観や思い込みだってあるわけですよ。時には間違っていたりもするわけです。これ自体は全然悪いものではなくて、本当に記事を書いてくれて人は善意で書いてくれていたり、翻訳してくれていたりするわけで、多くの日本のエンジニアに対して情報を公開してくれているので感謝しかないのです。だからね、僕はエンジニアとして、それらの記事に感謝しつつも、端折られている情報もあるので、いったんそういった記事を読んだあとは必ず情報発信元の記事を読もうよと、声を大にして言いたい。

ちょっと真面目な話、情報の発信元が英語圏の国なら英語で読んだ方が良いです。と言うのもですね、グローバル進出しているソフトウェアメーカーのサイトって親切に英語記事を日本語に翻訳したり、日本人向けに日本語の技術記事とか出してくれていたりするのですが、これって、まれに詳細が異なっていたりするんですよ。元々の記事を書いたエンジニアではなく、日本のローカルのエンジニアやマーケティングの方が2次情報として加工してしまっているのでちょっとニュアンスや細かいところが違うんです。あとはエンジニアじゃない方が技術記事書かれてるんだろうなって感じの物も散見されます。実際に手を動かして記事通りに実装していくと「おや?その説明だとこちらの実装と矛盾しない?」ってこと、結構あります。 と言うわけでね、 読もう!一次ソース!

え?発信元の記事を読んでも理解できない?

f:id:techsapp:20200307012310j:plain
ゴチャゴチャいうな!!!オレをこまらせたいかっ!!!

1: 外資系ソフトウェアメーカーのサポートではフロントラインとバックラインという体制に分かれているところが多いのではないかなと思います(あくまで僕の数社しかない外資経験の中ですが)。フロントラインが設定のチェックや過去類似事例からの回避策や恒久策の提示まで。フロントラインが解決できなかったものをバックラインがフォローしたり巻き取る。

ローカル通知の実装メモ(Android)

とりあえず前回プッシュ通知やってみるって言ったので、今回はローカル通知を実装した時のメモ。 プッシュ通知が来たときにぺろーんって通知が出したいよね。今回はListView内のアイテムをクリックしたら、ピコンっ!って通知が出るようにした。こんな感じね。

ちなみに2020年2月現在、Google playにアップロードできるAndroid API Levelが確か26以上だったかと思います。なので、以降のソースコードtargetSDKVersion 26以降を前提にしているのであしからず。

最低限の通知を作るには以下を構成します。

  1. ライブラリの追加
  2. 通知がタップされた時の動作定義
  3. ぺローンって出る通知の画面を作成
  4. ペローンって出る通知のチャネル作成/登録
  5. ペローンって通知を出す

Android 8(API Level 26) 以降って通知にチャネルって概念ができたのよね。今までは、アプリケーションの通知ってアプリ全体でOn/Offしか出来なかったんです。なので、LINEとかでAndroidの設定画面から通知をオフにしちゃうとLINEの通知全部届かなくなってました。でもAndroid 8(API Level 26)以降はチャネルという新しい枠組みができたので、「このトークの通知はオフ」「このトークの通知はオン」と言うような制御がAndroidのシステム側で出来るようになりました。1つのアプリ内でも様々な通知の種類があるので、例えば広告系のチャネル、とかアプリの更新のお知らせチャネルとか通知のチャネルを分けることによって、よりユーザーが通知のオン/オフを管理しやすくなってます。チャネルの作成/登録はAndroid 8 (API Level 26)から必須になっているので、この概念を理解する必要があります。

1.ライブラリの追加

さて、本題。まずは通知を作成するための標準ライブラリをgradleに追加しましょう。API 26以降ではこちらのandroidx.core:coreのライブラリを追加してあげてください。androidx.core:coreのバージョンは必要に応じて任意のバージョンにしてください。

app/build.gradle

    dependencies {
        ...
        implementation 'androidx.core:core:1.2.0'
    }

2.通知がタップされた時の動作定義

通知がタップされた際に、アプリのアクティビティを呼び出すためにIntentを定義しています。

            /**
             * Set an Action for Notification is tapped. In this case, when the notification is
             * tapped, the application will be launched.
             */

            Intent intent = new Intent(MainActivity.this, MainActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this,
                    0, intent, 0);

setFlags()で通知がタップされた際の動作を定義しています。もしアプリが起動していない状態でタップされるとFLAG_ACTIVITY_NEW_TASKでアプリが起動します。アプリが起動中の状態で通知がタップされるとFLAG_ACTIVITY_CLEAR_TASKとなり、デバイス戻るボタンが押されたのと同じように1つ前に戻る動作となります。最後にPendingIntentのオブジェクトを通知にセットすることで、通知がタップされた際にこのIntentからアプリが起動するようになります。ということで、次は

3.ぺローンって出る通知の画面を作成

ペローンって出す通知そのものの画面を作成です。これはちょー簡単。こんな感じ。

            /**
             * Configure Notification contents how it show at notification bar.
             */
            String CHANNEL_ID = "0";
            NotificationCompat.Builder nfBuilder = new NotificationCompat.Builder(
                    MainActivity.this, CHANNEL_ID)
                    .setSmallIcon(R.drawable.ic_sms_black_24dp)
                    .setContentTitle("Tapped ListView")
                    .setContentText("You tapped " + item + " in ListView...")
                    .setCategory(NotificationCompat.CATEGORY_MESSAGE)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(true);

先ほど作成しておいたPendingIntentsetContentIntent()にセットすると、通知をユーザーがタップした際にアクションが実行されます。 setCategory()はデバイスがサイレントモードの時の通知の動作を指定しています。 setAutoCancel()は通知がタップされた場合に通知が消えます。 NotificationCompat.Builderのチェーンメソッドの設定は、通知の以下の画面と紐づいています。

4.ペローンって出る通知のチャネル作成/登録

次に通知のチャネルを登録しておきます。ぶっちゃけチャネル名なんてどうでも良くて、適当な名前でチャネルを作れば良いんじゃないでしょうかね。

            /**
             * Create a channel for the notification and set importance for it.
             * User can configure whether the notification turns on or off by channels.
             */
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                    "ListView notification", NotificationManager.IMPORTANCE_HIGH);
            channel.setDescription("This channel is for ListView notification.");
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);

CHANNEL_IDはチャネルの種類を内部的に識別するためのString type のIDです。チャネル名と一致させておくと良いかと思います。NotificationManager.IMPORTANCE_HIGHは、通知を受信した際に、ピコンっ!ってAndroidの画面上部に通知を表示させたいときに設定します。HIGH以上の優先度にしないとステータスバーにアイコンが表示されるだけで、Heads-up通知のような動作はしません。

Heads-up notification  |  Android Developers

The heads-up notification appears the moment your app issues the notification and it disappears after a moment, but remains visible in the notification drawer as usual.

Example conditions that might trigger heads-up notifications include the following:

The user's activity is in fullscreen mode (the app uses fullScreenIntent). The notification has high priority and uses ringtones or vibrations on devices running Android 7.1 (API level 25) and lower. The notification channel has high importance on devices running Android 8.0 (API level 26) and higher.

5.ペローンって通知を出す

最後は先ほど作成した通知画面を出力します。

            int NOTIFICATION_ID = 0;
            NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(MainActivity.this);
            notificationManagerCompat.notify(NOTIFICATION_ID, nfBuilder.build());

NotificationManagerCompatにチャネルと、先ほど作成した通知画面をセットして、notifyメソッドを呼び出すと通知が表示されます。

ちなみにロック画面にも通知がこんな感じで表示されるようになります。

あと余談ですが、Android標準のアイコンを使ってアプリを作りたい場合(僕なんかはものぐさなので、自分でアイコンとか絶対作りたくないので出来合いで済ませたい)、こんな感じでプロジェクトのresディレクトリに標準のアイコンを追加できます。

1.Move to File > New > Vector Asset

2.Click an icon at "Clip Art"

3.Select an icon which you want to use and Click "OK"

4.Click "Next" 5.Click "Finish"

res ディレクトリに追加したアイコンはR値経由でこんな感じで呼び出せば良いかと思います。

            NotificationCompat.Builder nfBuilder = new NotificationCompat.Builder(
                    MainActivity.this, CHANNEL_ID)
                    .setSmallIcon(R.drawable.ic_android_black_24dp) // <--先ほど追加したアイコンはこれ
                    ...

通知のsmallアイコンがBugdroid君に変わりました。

f:id:techsapp:20200301003030p:plain
00 Bugdroid at Notificaiton
f:id:techsapp:20200301003326p:plain
01 Bugdroid at Notification

キーボードを新調した(Majestouch 2)

テレビやSNSを全くやらないのでつい最近まで全然知らなかったんですが、世の中ではコロナウィルスが流行っているんですね。Amazonが追加費用なしで配送してくれてネット環境さえあれば、本当に山に篭りたいくらい世捨て人なので世の中のことが全然分からないんですよね。会社のポリシーで海外への出張規制や会議の開催が規制されているのを知って、初めてコロナってやばいんじゃないかと思いました、はい。

そんなこんなで世の中的に働き方改革とかリモートワークがより一層推進されている感じなので、僕もその波に便乗して自宅勤務をもっと増やしてみようかなと思ってしまったんです。いや、もともと自宅勤務はやってたんですが、もうちょっと自宅勤務日を増やして、あわよくば人と会う機会を減らそうともっぱら目論んでいるわけです。ここだけの話、僕、人、嫌いなんですよ、実は。

自宅だとあまり立派な作業環境は置けないので、何インチだかよくわかりませんが、まぁデバッグやログトレースに不便はしない程度のサイズのモニタと、腰痛予防に奮発して買ったErgohuman Proの椅子(コレいいよね、また今度レビューしよう)と、安物のBruetoothのキーボートといった感じでそんなに不便はしないんです。しかしですね?本格的に自宅勤務の労働時間が増えるとちょっと状況が違うというか、会社の東プレの静音キーボード( REALFORCE91UBK-S えっ!?今って6万円もすんの!?これ!?)と自宅のよー分からんメーカーのキーボードの左下らへんのWindowsボタンとかCtrlボタンやら配置が違って微妙にストレスなわけです。あと、行頭、行末へのショートカットが違ったりね。それで持ってぼかぁ古い人間なのでLaptop内臓キーボードも打鍵が浅くてペチペチする感じがどうも苦手というか、顔に似合わず長年音楽やってたのでとにかく打鍵が強くてキーボードを破壊してしまうんですよ。それこそ打鍵はパチパチとかペチペチではなくてズゴんっ!ドゴんっ!なわけです。よくギャグなんかで最後にエンターキー「パシーんっ!」ってやるやつありますけど、僕の場合は「ズゴゴゴゴッ!ズガンッ!」なわけ。キーボード クラッシャーなわけ。なので、昔使ってたSonyVAIOとか買って1ヶ月ぐらいでEのボタンを破壊してめり込んでしまいましたしね。僕の打鍵が強すぎて破壊してしまったなんて何だかSony さんには申し訳なくて、保守交換してもらわずにそのままUSBでキーボード挿して6〜7年くらい使ってましたね。

まぁそれは良いとして、そんなわけでそういえば自宅勤務が増えるんですよ、話脱線して忘れてましたが。なので、いろいろ悩みましたよ。

そもそも自宅のPCはMacなので、よく分からんメーカーのWindowsMacに対応しているキーボードを使っていたわけで、特に自宅でたくさん文字を打ったりプログラミングをするわけではなかったのでコレでよかったのです。しかしながら自宅で仕事をするとなると東プレの静音キーボードと自宅のペチペチキーボードの落差が酷くて肩こりがひどいのです。

これは新たにMac対応のキーボードを買うべきか、いやいや、そもそもMac純正で僕の全体重がかかった打鍵に耐えるだけの製品ってあるんですっけ?いやない(はず)。ほならね、もう東プレもう一台買いますか?いやいや、あんな高いもんおいそれと買えません。でもそこそこちゃんとしたやつじゃないと日頃の自宅勤務に耐えられないわけですよ、キーボードが。じゃぁどうするのってーので、ほいこれ、1万円のレンジで買えるFILCO Majestouch 2 HAKUA TKL 静音 91日本語 CHERRY MXピンク軸メカニカルKB USB&PS/2 N-key マットホワイト FKBN91MPS/JMW2SHKにしました。

とにかく打鍵が強いので、それに耐えなければならないということと、音が出ないこと、Macでも使いたいので色は白がいいかしら?的なのりでコレにしてみました。いわゆるピンク軸という静音モデルの軸にしてみました。大事なことでもないですが何度も言いますよ?いいですか?

自分、打鍵うるさいんで。

で使ってみた感じ、というか今使っているんですが、タッチした感じはスコスコ打てて、打鍵の深さは3.7mmだけどきちんと打ってる感じはして良いです。もともと東プレの静音を使っていたのでスコスコ深く打てるキーボードが好きなんです。東プレは変化荷重なので、キーボードの真ん中が45gの重さ、端に行くにつれて軽くキータッチになるのですが、このMajestouch 2では全部45gなので、若干東プレより打鍵は重く感じます。

Majestouchのようなミドルレンジのキーボードを使ってみて思うのは、やっぱりハイエンドの東プレのキーボードってすんごいうち心地良いんだなと思いましたね。 もちろんMajestouchは1万円の価格帯にしては最高のできだと思います。ただ、今キーボードを部屋で叩いているのですが、夜になるとやはり結構打鍵音は気になる感じですね。あとは鉄板が入っているせいですが、キーボードを打ち込むと鉄板が共鳴して「カーン」って音が結構します。コレは僕の打鍵が強すぎるせいなのかどうかわかりませんが、夜中にキーボードを打つには結構周りに気を遣っちゃう感じではありますね。

そんなわけで、個人的には価格とクォリティのバランスから見てすごく満足しているのですが、思ったほど静音ではなかったって感じですかね。僕の中でガチでキーボード使うなら東プレ、キーボードこだわりたい、でも予算が、、、なときにCerry 軸系のキーボードはとても良い選択肢だと思いました。

みんなもキーボードいいやつ使うと文字打つのが楽しくなるからおすすめだよ〜!面白いと思ったらチャンネル登録よろしくね〜👆👆!!まった見ってね〜!🤗(Youtuber風終わり方)

Libraryの追加方法のメモ(Android Studio)

Android でリモートプッシュ通知とその逆にAndroid 端末からサーバーサイドへの応答ってどうやって実装されているんだろう?とう素朴な疑問から、ちょっと自分で実装してみようと久しぶりにAndroid Studioの開発環境を使うと様々な部分がupdateされていて、ライブラリの追加方法とか分かんなくなっちゃったのでメモ。

やり方は2通り合って、

  1. プロジェクトのlibsディレクトリにjarをぶち込む
  2. Android StudioGUIから追加する

いづれかかな。他にもあるのかもしれないけど。

 

1.の方法はずっと不変なので、とりあえずこれだけ覚えておけばいつでも使えるでしょう。

  1. Move to Project > Gradle Scripts 
  2. Right click "build.gradle(Module: app)"
  3. Select "Copy Path"
  4. For Mac OS,
  5. Open "Finder" and push "command + shift + G"
  6. Enter the path where you copied at step 3
  7. Move to "~project name/app/libs" directory

f:id:techsapp:20200224221807p:plain

gradle Module app

ここのlibsディレクトリに好きなライブラリのjarファイルを置いておけば利用できる。

これは、gradleファイルの以下で設定しているからで、[libs]ディレクトリの[*.jar]を読めよと設定されているから。

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])

 なので、ここでディレクトリ名を変更したら、実際のディレクトリ上でも同名のディレクトリを作成しておけば、任意の名前のディレクトリにライブラリを配置することもできる。

 次に2つ目のGUIでのライブラリの追加方法について。

  1. 同様にModule: appのgradle ファイルを開き、
  2. Move to Project > Gradle Scripts 
  3. Right click "build.gradle(Module: app)"
  4. Click "Open Project Structure"
  5. Move to Dependancies > app
  6. Click "+" button in "Declared Dependancies"(not in Modules > app)

f:id:techsapp:20200224222012p:plain

Project Structure

 

で"1. Library Dependancy"を選択するとGoogleやJCenterのリポジトリ上のライブラリを検索して追加することができ、"2. Jar Dependancy" を選択した場合、jarやaarの配置されているローカルディレクトリを選択することで、ライブラリを追加できる。

今回はとりあえず通知機能を実装したかったらandroidx.coreをGoogleリポジトリから追加した。

 

ちなみに本筋からちょっとずれるけど、

developer.android.com


ここの通知作成のチュートリアルにある

サポート ライブラリを追加する

Android Studio で作成されたほとんどのプロジェクトには、NotificationCompat を使用するために必要な依存関係が含まれていますが、モジュール レベルの build.gradle ファイルに次の依存関係が含まれていることを確認する必要があります。

    dependencies {
         implementation "com.android.support:support-compat:28.0.0"
    } 

 で指定されているライブラリはちょっと古くてgradleで指定するとWarnigがでてsyncできません。なので、新しいライブラリに書き換えて利用した方が良いです。新しいライブラリはAndroidxとなるので、以下の古いライブラリとAndroidxのマッピングをみながら古いライブラリから置き換えると良いです。

 

developer.android.com

 

うーん、記事書いて思ったのは、コードとか書くからMarkdown記法マスターした方が良さそうね。

Qiitaの投稿されたクレーム記事について(そもそもQiitaってそんなサービスだっけ?)

Qiita にこんな記事が。

qiita.com

そもそもQiitaはこのような記事を掲載する場所ではないので、Twitterか個人的なブログに記載してもらいたいというのは置いておいて、サポート兼エンジニアとしていくつか気になった点を書いてみます。

「あれれ。自分宛てにCCで送ったメールに添付されているZIPファイルは、問題なく展開できるのにな。特定の宛先だけファイル破損なんてあるのかな」と、この時点で少々嫌な不安を感じつつ、

 これはToやCcに指定されたメールアドレスのドメインが異なれば当然各宛先のメールルーティングも異なるので、論理的に十分あり得る事象でしょう。例えば、ルーティング先のメールゲートウェイにウィルススキャン機能なんかがあったりすると、添付ファイルを壊してしまうこともあるので「特定の宛先だけファイル破損なんてあるのかな」という問いに対しては「あり得ます」となります。

ご提示いただいたファイルは.mht形式のため、Dropboxのwebサイト上でプレビューすることができませんでした。
次のヘルプセンターにてプレビュー可能なファイル形式をご確認いただけますので、こちらの形式でお送りいただけますでしょうか。
https://www.dropbox.com/help/files-folders/file-types-that-preview

「ん? Dropbox上にはそういう制限があるのか。なんか言ってることよくわからないな」とイライラしつつも、今度は、zipを展開して中身にあった.mht形式のファイルをメールに添付して送りました。

 この方はサポートの提示したURLを読まなかったのでしょうか。URLを読めば.mht形式は使えないことがすぐに分かるので、普通の人のコミュニケーションならこの時点で「資料採取に指定された方法だと.mht形式のファイルが生成されるが、Dropboxではプレビューできない形式のようだ。本当にpsrでの資料採取で良いのか?」という確認をするかと思いますが、文にある通り、この時点でかなりのフラストレーションを抱えているようなので、もはやサポートの指示に耳を貸す気がなくなってしまっているようです。

これでわかりました。このCSの人たちが使っているのは、Macなんでしょう。Macは.mht形式のHTMLファイルは扱えないみたいですから。

 フラストレーションから冷静さを欠いてしまっているのでしょう。これは先入観かと思います。Dropboxのプレビューで表示されるファイル形式でしかトラブルシュートの資料を受け取れないとサポートが言っているので、Macかどうかというのは今回は関係のない話でしょう。

 

この方の記事を読む限りだと(相手の言い分や実際のやりとりは分からないので)、私もサポート側の初動ミスだと思います。さらにお客様からの質問に対して無視するというのは最悪の対応でしょう。ミスのポイントを並べると

  1. 間違った資料の採取方法を案内した
  2. 間違ったことに対して謝罪せずに次の案内に進んだ
  3. 質問を無視した

でしょうか。結果、この方の疑心暗鬼をうみ、先入観や冷静さを欠いた状況にさせてしまっているように見えます。往々にして怒っているお客様は、自分を納得させる、相手を責めるための質問を大量にしてきます。これらの質問はビジネス上意味のないかつ、とても細かい質問が多いです。これらに時間をかけて一生懸命回答したとしても、ビジネス上一円の利益にもならないでしょう。これらの意味のないやりとりに付き合うのは時間の無駄でしかないので、このような事態にならないように立ち回るよう心がける必要があります。

 

サポートも人間なのでミスはします。なので、ミスした場合はすぐに謝罪すれば結構物事がスムーズに進んだりします。例えば、今回の場合、上述の2.の時点で

  • 提案した資料採取の方法が誤っていたことを謝罪
  • (だから)Dropbox上でプレビュー可能な資料で調査を行うこと
  • すでに頂いている資料から調査を進めること

を伝えていれば、このような事態にはならなかったのかなと思いました。謝って物事がうまく進むのであれば、ガンガン謝りましょう。もし自分で謝りにくかったら、より上位の人に謝ってもらっても良いかもしれませんね。

 

基本的にサポートはクレーム対応に時間をかけるのは悪です。本当に我々サポートの力が必要なお客様に時間をかけなければなりません。クレーマの対応で懇切丁寧に無意味な回答を出したとして、果たしてその人は我々の会社にお金を追加で落としてくれるでしょうか。

 

誤解の無いように言っておきますが、サポート側のミスはミスです。認めましょう。謝りましょう。問題はクレーム対応に「時間をかけること」です。

 

我々は慈善事業ではないので、お金を落としてくれる人がお客様です。お金を出してくれている人の意味のある問い合わせに時間をかけなくてはなりません。クレーム対応で意味のない回答をしている間は、お金を出してくれるお客様に意味のある対応ができない状況になります。

なので、日頃から

  • クレームが発生しないよう立ち回る
  • クレームが発生したら謝罪して時間をかけない努力をする

 必要があるでしょう。

最後に、

私はDropboxの有料ユーザーではありません。ですから、そのサービスに対して、Dropbox社が私に責任を負う必要がないのは明白です。

 この方も無料ユーザーということで、この会社に対して責任はないとは言っていますが、

しかし、先方の指示によって私が作業した労力に対しては、責任を負う必要はあるんじゃないでしょうか? 問い合わせた問題そのものは解決したんだから、そのやり取りの中での不手際はもういいだろ、という態度には納得いきません。

とのこと。無料ユーザーだから会社に責任はないと前半で言いつつ、後半は納得いかないからやっぱり責任はあるのだそうです。 そもそも無料ユーザー向けに問い合わせ窓口がなかった場合、この方の問題は解決しなかったわけですが、その場合はどういう主張になるのでしょうか。この方にとって問い合わせ窓口は「サービス」には含まれないのでしょうか。

ご自身で辻褄の合わないことをおっしゃっているので、サポートが真面目に時間をかける必要はないのです。この時点で「問題を解決したい」のではなく「相手を責めたい/謝らせたい」に変わっています。なので、謝って済ませるのが賢いやり方だと個人的に思います。それにこのような記事をQiitaに投稿するぐらいですから(Qiitaのガイドラインを未読もしくは無視するような方なので、あまりお行儀の良い方ではないのでしょう)、製品アンチなはずなので今後製品にお金を使ってくれることはまずないでしょうから。

 

でもこういう人って文句を言いながら使い続けるんですよね、無料で。。。

 

※ 7th Mar 2020

いつのまにかQiitaの元記事が運営によって非公開にされましたね。