2016/12/28

Android Studio でモジュールを削除する方法

Android Studioチェックしたバージョンは 2.2.3 でモジュールを削除しようとする時、
モジュールを右クリックしてコンテキストメニューを探してしまったことが一度くらいあるはず。
ところが、コンテキストメニューには "Delete" という項目はないのです。

では、どう削除するのかというと、"Project Structure..." メニューから削除できます。

File → Project Structure...
Modules で 対象のモジュールを選択し、"Delete" ボタン(マイナスのアイコン) を押す。
知っていれば何てこと無いのだけど、ちょっと直感的ではないです。 > 参考 > - [ide - How to delete a module in Android Studio - Stack Overflow](http://stackoverflow.com/questions/16710290/how-to-delete-a-module-in-android-studio) 参考リンクを見るとわかるように、仕様がどんどん変わっているようなので、そのうちコンテキストメニューに入るかもしれません。

2016/12/27

apk の署名を確認する方法2種

基本的には `keytool` を使っておけば良いと思うのですが、 `apksigner` でも確認出来たのでメモ。

署名済みの apk から署名を削除する方法

Debug Keystore で署名済みの apk が送られてきちゃった。みたいな事は時々あると思うのですが、そういう時は署名を削除して再署名すれば良いのです。

### apk の署名とは
apk の署名は以下の 3つのファイルで構成されています各ファイルの役割については参考リンクが詳しいので、そちらを参照してください。
そのため、これらのファイルを削除すれば、未署名の apk になります。

- META-INF/MANIFEST.MF
- META-INF/CERT.RSA
- META-INF/CERT.SF

注: CERT.RSA と CERT.SF は別の名前(ANDROID.RSA 等)になっている場合があります。

> 参考
> - [APK ファイルの署名の仕様 - urandroid](http://d.hatena.ne.jp/urandroid/20110818/1313656536)


### 署名を削除する
コマンドラインだと以下のようにすると良いでしょう。

```console
$ zip -d app-debug.apk "META-INF/*"
deleting: META-INF/CERT.RSA
deleting: META-INF/CERT.SF
deleting: META-INF/MANIFEST.MF
```

この方法だと `META-INF` ディレクトリ自体を削除してしまうのですが、apk の場合 `META-INF` にこれ以外のファイルが入ることは無さそうなのであくまで経験則。要確認。、これで大丈夫だと思われます。

以下のように `apksigner verify` をするとエラーが出ます。

```console
$ apksigner verify app-debug.apk
DOES NOT VERIFY
ERROR: Missing META-INF/MANIFEST.MF
```

> 参考
> - [apksigner | Android Studio](https://developer.android.com/studio/command-line/apksigner.html)

### 再署名する
未署名の apk に後から署名する方法がそのまま使えます。
`zipalign` を忘れないようにしましょう。

[未署名の apk に後から署名する方法 | 穀風](https://kokufu.blogspot.jp/2016/12/apk.html)

apksigner で未署名の apk に後から署名する方法

未署名の apk に署名するツールは、build-tools 24.0.3 以降から `jarsigner` の代わりに `apksigner` を使うようになりました。
`zipalign` の実行順序など細かいところが変わっていますのでご注意ください。

なお、署名済みの apk を未署名にする方法は以下を参照してください。

> 参考
> - [署名済みの apk から署名を削除する方法 | 穀風](http://kokufu.blogspot.jp/2016/12/apk_27.html)


### Overview
全体の流れとしては以下のようになります。

- zip のアライメント調整
- 署名
- 検証

具体的には以下。

```console
`gutter: false;
$ zipalign -v -p 4 my-app-unsigned.apk my-app-unsigned-aligned.apk
$ apksigner sign --ks ~/.android/my-key.jks --ks-key-alias alias-name --out my-app.apk my-app-unsigned-aligned.apk
$ apksigner verify my-app.apk
```

`apksigner` と `zipalign` は `android-sdk/build-tools/XX.X.X/` にあり、ここではパスが通ってることとします実際には、build-tools のバージョン指定があってパスを通すのは結構面倒。

> 参考
>
> - [アプリに署名する | Android Studio](https://developer.android.com/studio/publish/app-signing.html#signing-manually)
> - [android - how to sign an already compiled APK - Stack Overflow](http://stackoverflow.com/questions/10930331/how-to-sign-an-already-compiled-apk)

一度経験すれば上記で十分だと思いますが、一応各手順の説明を書いておきます。


### zipalign
署名する前に zip のアライメントを整える必要がありますbuild-tools 24.0.2 以前の `zipalign` は `jarsigner` の実行以降に行っていたが、`apksigner` は実行前に行うとのこと。

```console
`gutter: false;
$ zipalign -v -p 4 my-app-unsigned.apk my-app-unsigned-aligned.apk
```

- `-v` 冗長な情報表示
- `-p` 全ての共有ファイルで同じアライメントを使う
- `4` アライメント [byte]、少なくとも現在は 4 固定

> 参考
> - [zipalign | Android Studio](https://developer.android.com/studio/command-line/zipalign.html)


### 署名
署名ファイル `my-key.jks` は既に作成済みとします。作成方法は参考リンクを参照してください上のほうに Android Studio での作成方法も書いてあります。

```console
`gutter: false;
$ apksigner sign --ks ~/.android/my-key.jks --ks-key-alias alias-name --out my-app.apk my-app-unsigned-aligned.apk
```

`--out` を指定しなかった場合、元のファイルに上書きされます。
他の項目は自明ということで。

> 参考
> - [アプリに署名する | Android Studio](https://developer.android.com/studio/publish/app-signing.html#signing-manually)
> - [apksigner | Android Studio](https://developer.android.com/studio/command-line/apksigner.html)


### 検証
最後に `apksigner` を利用して検証します。

```console
`gutter: false;
$ apksigner verify my-app.apk
```

成功した場合、何も表示されないので注意が必要です。

以下のように `-v` か `--print-certs` をつけた方がわかりやすいかもしれません。

```console
`gutter: false;
$ apksigner verify -v app-debug.apk
Verifies
Verified using v1 scheme (JAR signing): true
Verified using v2 scheme (APK Signature Scheme v2): true
Number of signers: 1
```

```console
`gutter: false;
$ apksigner verify --print-certs app-debug.apk 
Signer #1 certificate DN: CN=Android Debug, O=Android, C=US
Signer #1 certificate SHA-256 digest: ca17bec5dd187fdb4a859b22f5db82b5251ab68b041df5b05dd885432771d5cd
Signer #1 certificate SHA-1 digest: 13199c0c7fdf8734d904925f5aa425c537cf8e69
Signer #1 certificate MD5 digest: ef94f75750de7d124796eb7c5ed38cf2
```

2016/12/20

Android の build.prop に設定値を追加する方法

Android のシステムプロパティを設定する方法は多々あります。

> 参考
>
> [システムプロパティのあれこれ | まくまく Android ノート](http://maku77.github.io/android/vendor/system-property.html)

その中でもデバイス固有のプロパティを記述するのが `/system/build.prop`。

OS を独自ビルドするような仕事をしていると、この `/system/build.prop` に設定値を追加したいことがあるのですが、このファイルの元になる情報が分散しているので、まとめておきます。

2016/12/15

MM-BTUD44 を Ubuntu 16.04 で使ってみた

Bluetooth ドングル [MM-BTUD44](http://amzn.to/2hvA2Fn) を買ってみました。
Ubuntu は対応OS に含まれていませんが、私のマシンでは問題なく使えました。 マザーボードは Intel H97 系の [GIGABYTE GA-H97-D3H](http://amzn.to/2hPRQrl) あくまで、私の環境では動作したという報告になります。 メーカーのサポート対象ではないので、ご購入の際はあくまで **自己責任** でお願いしますお約束

2016/12/03

Android で Wi-Fi Access Point との接続状態変化をイベントとして取得する


> この記事は [Android の Wi-Fi 実装に関する情報のまとめ](http://kokufu.blogspot.jp/2016/10/android-wi-fi_19.html) の一部として書かれました

Wi-Fi の接続状態をイベントとして取得するには `"android.net.wifi.STATE_CHANGE"` action を監視する `BroadcastReceiver` を使います。

`"android.net.wifi.WIFI_STATE_CHANGED"` という action もありますが、こちらは、Wi-Fi 機能の状態変化を見るものです。
非常に紛らわしいので注意が必要です。

> 参考
>
> [穀風: Android で Wi-Fi 機能の有効・無効の変化をイベントとして取得する](http://kokufu.blogspot.jp/2016/10/android-wi-fi_20.html)

### BroadcastReceiver のコード
`NetworkInfo` が Extra として渡されるので、接続状態を確認することができます。

```java
public class WifiConnectionWatcher extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { // "android.net.wifi.STATE_CHANGE"
            NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
            switch (info.getState()) {
                case DISCONNECTED:
                    break;
                case SUSPENDED:
                    break;
                case CONNECTING:
                    break;
                case CONNECTED:
                    break;
                case DISCONNECTING:
                    break;
                case UNKNOWN:
                    Log.e(TAG, "Wifi connection state is UNKNOWN");
                    break;
                default:
                    Log.e(TAG, "Wifi connection state is OTHER");
                    break;
            }
        }
    }
}
```

> 参考
>
> [穀風: Android で Wi-Fi の接続状態を確認する](http://kokufu.blogspot.jp/2016/10/android-wi-fi-access-point_27.html)


### 登録方法1
AndroidManifest.xml に登録する方法

常に変化を監視したい場合は、以下のように `BroadcastReceiver` を AndroidManifest.xml に追記します。

```xml

    
        
    

```

### 登録方法2
コードで登録する方法

特定の Activity が起動している間だけ監視したい場合などは、以下のように動的に登録します。

```java
    // Activity 等の Context の中で
    WifiConnectionWatcher mWifiConnectionWatcher = new WifiConnectionWatcher();

    @Override
    protected void onResume() {
        super.onResume();

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); // "android.net.wifi.STATE_CHANGE"

        registerReceiver(mWifiConnectionWatcher, intentFilter);
    }

    @Override
    protected void onPause() {
        super.onPause();

        unregisterReceiver(mWifiConnectionWatcher);
    }
```

### パーミッション
このコードを実行するのに特別なパーミッションは必要ありません。

2016/12/02

Android で Wi-Fi Access Point との接続を切断する


> この記事は [Android の Wi-Fi 実装に関する情報のまとめ](http://kokufu.blogspot.jp/2016/10/android-wi-fi_19.html) の一部として書かれました

### 接続切断の方法は2種類ある
Wi-Fi Access Point との接続を切断するには `WifiManager.disconnect()` もしくは  `WifiManager.disableNetwork()` を使用します。

`WifiManager.disconnect()` を使用した場合、状態は "Saved"日本語だと「保存済み」 になります。
`WifiManager.disableNetwork()` を使用した場合、状態は "Disabled"日本語だと「無効」になります。
"Disabled" といっても、登録してあるパスワード等が消えてしまったわけではありません。 設定画面から "Connect" をクリックしたり、 `WifiManager.enableNetwork()` を使用することでパスワード入力無しに再接続することが可能です。 ### 違いはあるようで無い では何が違うのかというと、**自動で** 再接続するかどうかのようです。 "Saved" の場合、何らかのタイミングで OS が再接続を試みる可能性がありますが、"Disabled" の場合はユーザーもしくは、`android.permission.CHANGE_WIFI_STATE` パーミッションを持ったアプリが意思を持って接続しない限り再接続されません。 ただし、後述のようにデバイスを再起動した場合は "Disabled" でも再接続されるので、完全に無効化するわけではないようです。 > 参考 > > [Android - What´s the difference between WifiManager disableNetwork() and disconnect() - Stack Overflow](http://stackoverflow.com/questions/30094055/android-what%C2%B4s-the-difference-between-wifimanager-disablenetwork-and-disconn) また、"Saved" もどのタイミングで再接続されるのかは不定のようです。 上記のサイトでは `WifiManager.disconnect()` を呼んでから数秒後に再接続されたとありますが、 私の Nexus 7 (2012)Android 4.4.4 では 一度 "Saved" 状態になると自動で再接続はされませんでした一度 Wi-Fi の圏外に出る等いろいろやってみたのですが。 ただし、デバイスを再起動すると接続されます。これは "Disabled" でも同じ。 結局、私の Nexus 7 では、これらの違いがよくわかりませんでした。 コードで Wi-Fi の接続を制御したい場合、勝手に再接続されることはあまり想定しないと思われるので、 `WifiManager.disableNetwork()` を使っておくのが無難でしょう。 ### コード1 `WifiManager.disconnect()` を使用する方法です。 ```java // Activity 等の Context 内で WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE); boolean succeeded = wm.disconnect(); ``` ### コード2 `WifiManager.disableNetwork()` を使用する方法です。 引数として Network ID が必要ですので、 `WifiManager.getConnectionInfo()` を使用して接続している Access Point の情報を取得します。 ```java // Activity 等の Context 内で WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE); WifiInfo wifiInfo = wm.getConnectionInfo(); boolean succeeded = wm.disableNetwork(wifiInfo.getNetworkId()); ``` 未接続状態でも `wifiInfo` は `null` にならず、Network ID が `-1` のインスタンスが返ってきます。 > 参考 > > [穀風: Android で 接続している Wi-Fi Access Point の情報を取得する](https://kokufu.blogspot.jp/2016/11/android-access-point.html) ### パーミッション `WifiManager.disconnect()` や `WifiManager.disableNetwork()` を実行するには `android.permission.CHANGE_WIFI_STATE` パーミッションを AndroidManifest.xml で設定する必要があります。 ```xml ``` また、 `WifiManager.getConnectionInfo()` を実行するには `android.permission.ACCESS_WIFI_STATE` パーミッションを AndroidManifest.xml で設定する必要があります。 ```xml ```

2016/12/01

Android Support Library のバージョン一覧を取得する

使用できる Support Library のバージョン一覧は maven レポジトリの中を参照することで可能です。