2016/12/28

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

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

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

File → Project Structure...

Modules で 対象のモジュールを選択し、"Delete" ボタン(マイナスのアイコン) を押す。

知っていれば何てこと無いのだけど、ちょっと直感的ではないです。

参考

参考リンクを見るとわかるように、仕様がどんどん変わっているようなので、そのうちコンテキストメニューに入るかもしれません。

  1. チェックしたバージョンは 2.2.3 
?
2016/12/27

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

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

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

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

apk の署名とは

apk の署名は以下の 3つのファイルで構成されています1。 そのため、これらのファイルを削除すれば、未署名の apk になります。

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

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

参考

署名を削除する

コマンドラインだと以下のようにすると良いでしょう。

1
2
3
4
$ 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 にこれ以外のファイルが入ることは無さそうなので2、これで大丈夫だと思われます。

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

1
2
3
$ apksigner verify app-debug.apk
DOES NOT VERIFY
ERROR: Missing META-INF/MANIFEST.MF

参考

再署名する

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

未署名の apk に後から署名する方法 | 穀風

  1. 各ファイルの役割については参考リンクが詳しいので、そちらを参照してください 
  2. あくまで経験則。要確認。 
?

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

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

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

参考

Overview

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

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

具体的には以下。

$ 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

apksignerzipalignandroid-sdk/build-tools/XX.X.X/ にあり、ここではパスが通ってることとします1

参考

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

zipalign

署名する前に zip のアライメントを整える必要があります2

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

参考

署名

署名ファイル my-key.jks は既に作成済みとします。作成方法は参考リンクを参照してください3

$ apksigner sign --ks ~/.android/my-key.jks --ks-key-alias alias-name --out my-app.apk my-app-unsigned-aligned.apk

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

参考

検証

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

$ apksigner verify my-app.apk

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

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

$ 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
$ 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
  1. 実際には、build-tools のバージョン指定があってパスを通すのは結構面倒 
  2. build-tools 24.0.2 以前の zipalignjarsigner の実行以降に行っていたが、apksigner は実行前に行うとのこと 
  3. 上のほうに Android Studio での作成方法も書いてあります 
?
2016/12/20

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

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

参考

システムプロパティのあれこれ | まくまく Android ノート

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

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

2016/12/15

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

Bluetooth ドングル MM-BTUD44 を買ってみました。

Ubuntu は対応OS に含まれていませんが、私のマシンでは問題なく使えました。

マザーボードは Intel H97 系の GIGABYTE GA-H97-D3H

あくまで、私の環境では動作したという報告になります。 メーカーのサポート対象ではないので、ご購入の際はあくまで 自己責任 でお願いします1

  1. お約束 
?
2016/12/03

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

この記事は Android の Wi-Fi 実装に関する情報のまとめ の一部として書かれました

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

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

参考

穀風: Android で Wi-Fi 機能の有効・無効の変化をイベントとして取得する

BroadcastReceiver のコード

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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 の接続状態を確認する

登録方法1

AndroidManifest.xml に登録する方法

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

1
2
3
4
5
<receiver android:name=".WifiConnectionWatcher">
    <intent-filter>
        <action android:name="android.net.wifi.STATE_CHANGED" />
    </intent-filter>
</receiver>

登録方法2

コードで登録する方法

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 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 実装に関する情報のまとめ の一部として書かれました

接続切断の方法は2種類ある

Wi-Fi Access Point との接続を切断するには WifiManager.disconnect() もしくは WifiManager.disableNetwork() を使用します。

WifiManager.disconnect() を使用した場合、状態は "Saved"1 になります。

WifiManager.disableNetwork() を使用した場合、状態は "Disabled"2になります。

"Disabled" といっても、登録してあるパスワード等が消えてしまったわけではありません。 設定画面から "Connect" をクリックしたり、 WifiManager.enableNetwork() を使用することでパスワード入力無しに再接続することが可能です。

違いはあるようで無い

では何が違うのかというと、自動で 再接続するかどうかのようです。 "Saved" の場合、何らかのタイミングで OS が再接続を試みる可能性がありますが、"Disabled" の場合はユーザー3が意思を持って接続しない限り再接続されません。 ただし、後述のようにデバイスを再起動した場合は "Disabled" でも再接続されるので、完全に無効化するわけではないようです。

参考

Android - What´s the difference between WifiManager disableNetwork() and disconnect() - Stack Overflow

また、"Saved" もどのタイミングで再接続されるのかは不定のようです。 上記のサイトでは WifiManager.disconnect() を呼んでから数秒後に再接続されたとありますが、 私の Nexus 7 (2012)4 では 一度 "Saved" 状態になると自動で再接続はされませんでした5

ただし、デバイスを再起動すると接続されます。これは "Disabled" でも同じ。 結局、私の Nexus 7 では、これらの違いがよくわかりませんでした。

コードで Wi-Fi の接続を制御したい場合、勝手に再接続されることはあまり想定しないと思われるので、 WifiManager.disableNetwork() を使っておくのが無難でしょう。

コード1

WifiManager.disconnect() を使用する方法です。

1
2
3
// Activity 等の Context 内で
WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE);
boolean succeeded = wm.disconnect();

コード2

WifiManager.disableNetwork() を使用する方法です。

引数として Network ID が必要ですので、 WifiManager.getConnectionInfo() を使用して接続している Access Point の情報を取得します。

1
2
3
4
5
// Activity 等の Context 内で
WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE);
WifiInfo wifiInfo = wm.getConnectionInfo();
 
boolean succeeded = wm.disableNetwork(wifiInfo.getNetworkId());

未接続状態でも wifiInfonull にならず、Network ID が -1 のインスタンスが返ってきます。

参考

穀風: Android で 接続している Wi-Fi Access Point の情報を取得する

パーミッション

WifiManager.disconnect()WifiManager.disableNetwork() を実行するには android.permission.CHANGE_WIFI_STATE パーミッションを AndroidManifest.xml で設定する必要があります。

1
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE">

また、 WifiManager.getConnectionInfo() を実行するには android.permission.ACCESS_WIFI_STATE パーミッションを AndroidManifest.xml で設定する必要があります。

1
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE">

  1. 日本語だと「保存済み」 
  2. 日本語だと「無効」 
  3. もしくは、android.permission.CHANGE_WIFI_STATE パーミッションを持ったアプリ 
  4. Android 4.4.4 
  5. 一度 Wi-Fi の圏外に出る等いろいろやってみたのですが 
?
2016/12/01

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

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