adb コマンドで 補完 させる

Cross_Reference___sdk_bash_completion_adb_bash

adb コマンドがめんどくさい場合は
コマンドを補完(completion)してもらいましょう.

何が補完できるか.

・オプション
・サブコマンド
・デバイスにインストールしているパッケージ名
・ローカル/リモートファイル名
・パソコンに接続しているデバイスシリアル名
...

# /* vim: set ai ts=4 ft=sh: */
#
# Copyright 2011, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

_adb() {
    unset -v have
    type $1 &> /dev/null && have="yes"

    if [ "$have" != "yes" ]; then
        return
    fi

    local where i cur serial
    COMPREPLY=()

    serial="${ANDROID_SERIAL:-none}"
    where=OPTIONS
    for ((i=1; i <= COMP_CWORD; i++)); do
        cur="${COMP_WORDS[i]}"
        case "${cur}" in
            -s)
                where=OPT_SERIAL
                ;;
            -p)
                where=OPT_PATH
                ;;
            -*)
                where=OPTIONS
                ;;
            *)
                if [[ $where == OPT_SERIAL ]]; then
                    where=OPT_SERIAL_ARG
                elif [[ $where == OPT_SERIAL_ARG ]]; then
                    serial=${cur}
                    where=OPTIONS
                else
                    where=COMMAND
                    break
                fi
                ;;
        esac
    done

    if [[ $where == COMMAND && $i -ge $COMP_CWORD ]]; then
        where=OPTIONS
    fi

    OPTIONS="-d -e -s -p"
    COMMAND="devices connect disconnect push pull sync shell emu logcat lolcat forward jdwp install uninstall bugreport help version start-server kill-server get-state get-serialno status-window remount reboot reboot-bootloader root usb tcpip"

    case $where in
        OPTIONS|OPT_SERIAL|OPT_PATH)
            COMPREPLY=( $(compgen -W "$OPTIONS $COMMAND" -- "$cur") )
            ;;
        OPT_SERIAL_ARG)
            local devices=$(command adb devices 2> /dev/null | grep -v "List of devices" | awk '{ print $1 }')
            COMPREPLY=( $(compgen -W "${devices}" -- ${cur}) )
            ;;
        COMMAND)
            if [[ $i -eq $COMP_CWORD ]]; then
                COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") )
            else
                i=$((i+1))
                case "${cur}" in
                    install)
                        _adb_cmd_install "$serial" $i
                        ;;
                    pull)
                        _adb_cmd_pull "$serial" $i
                        ;;
                    push)
                        _adb_cmd_push "$serial" $i
                        ;;
                    reboot)
                        if [[ $COMP_CWORD == $i ]]; then
                            args="bootloader recovery"
                            COMPREPLY=( $(compgen -W "${args}" -- "${COMP_WORDS[i]}") )
                        fi
                        ;;
                    shell)
                        _adb_cmd_shell "$serial" $i
                        ;;
                    uninstall)
                        _adb_cmd_uninstall "$serial" $i
                        ;;
                esac
            fi
            ;;
    esac

    return 0
}

_adb_cmd_install() {
    local serial i cur where

    serial=$1
    i=$2

    where=OPTIONS
    for ((; i <= COMP_CWORD; i++)); do
        cur="${COMP_WORDS[i]}"
        case "${cur}" in
            -*)
                where=OPTIONS
                ;;
            *)
                where=FILE
                break
                ;;
        esac
    done

    cur="${COMP_WORDS[COMP_CWORD]}"
    if [[ $where == OPTIONS ]]; then
        COMPREPLY=( $(compgen -W "-l -r -s" -- "${cur}") )
        return
    fi

    _adb_util_complete_local_file "${cur}" '!*.apk'
}

_adb_cmd_push() {
    local serial IFS=$'\n' i cur

    serial=$1
    i=$2

    cur="${COMP_WORDS[COMP_CWORD]}"

    if [[ $COMP_CWORD == $i ]]; then
        _adb_util_complete_local_file "${cur}"
    elif [[ $COMP_CWORD == $(($i+1)) ]]; then
        if [ "${cur}" == "" ]; then
            cur="/"
        fi
        _adb_util_list_files $serial "${cur}"
    fi
}

_adb_cmd_pull() {
    local serial IFS=$'\n' i cur

    serial=$1
    i=$2

    cur="${COMP_WORDS[COMP_CWORD]}"

    if [[ $COMP_CWORD == $i ]]; then
        if [ "${cur}" == "" ]; then
            cur="/"
        fi
        _adb_util_list_files $serial "${cur}"
    elif [[ $COMP_CWORD == $(($i+1)) ]]; then
        _adb_util_complete_local_file "${cur}"
    fi
}

_adb_cmd_shell() {
    local serial IFS=$'\n' i cur
    local -a args

    serial=$1
    i=$2

    cur="${COMP_WORDS[i]}"
    if [ "$serial" != "none" ]; then
        args=(-s $serial)
    fi

    if [[ $i -eq $COMP_CWORD && ${cur:0:1} != "/" ]]; then
        paths=$(command adb ${args[@]} shell echo '$'PATH 2> /dev/null | tr -d '\r' | tr : '\n')
        COMMAND=$(command adb ${args[@]} shell ls $paths '2>' /dev/null | tr -d '\r' | {
            while read -r tmp; do
                command=${tmp##*/}
                printf '%s\n' "$command"
            done
        })
        COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") )
        return 0
    fi

    i=$((i+1))
    case "$cur" in
        ls)
            _adb_shell_ls $serial $i
            ;;
        /*)
            _adb_util_list_files $serial "$cur"
            ;;
        *)
            COMPREPLY=( )
            ;;
    esac

    return 0
}

_adb_cmd_uninstall() {
    local serial i where cur packages

    serial=$1
    i=$2
    if [ "$serial" != "none" ]; then
        args=(-s $serial)
    fi

    where=OPTIONS
    for ((; i <= COMP_CWORD; i++)); do
        cur="${COMP_WORDS[i]}"
        case "${cur}" in
            -*)
                where=OPTIONS
                ;;
            *)
                where=FILE
                break
                ;;
        esac
    done

    cur="${COMP_WORDS[COMP_CWORD]}"
    if [[ $where == OPTIONS ]]; then
        COMPREPLY=( $(compgen -W "-k" -- "${cur}") )
    fi

    packages="$(
        command adb ${args[@]} shell pm list packages '2>' /dev/null 2> /dev/null | tr -d '\r' | {
            while read -r tmp; do
                local package=${tmp#package:}
                echo -n "${package} "
            done
        }
    )"

    COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "${packages}" -- "${cur}") )
}

_adb_shell_ls() {
    local serial i cur file
    local -a args

    serial=$1
    i=$2
    if [ "$serial" != "none" ]; then
        args=(-s $serial)
    fi

    where=OPTIONS
    for ((; i <= COMP_CWORD; i++)); do
        cur="${COMP_WORDS[i]}"
        case "${cur}" in
            -*)
                where=OPTIONS
                ;;
            *)
                where=FILE
                break
                ;;
        esac
    done

    file="${COMP_WORDS[COMP_CWORD]}"
    if [[ ${file} == "" ]]; then
        file="/"
    fi

    case $where in
        OPTIONS)
            COMPREPLY=( $(compgen -W "$OPTIONS" -- "$cur") )
            _adb_util_list_files $serial "$file"
            ;;
        FILE)
            _adb_util_list_files $serial "$file"
            ;;
    esac

    return 0
}

_adb_util_list_files() {
    local serial dir IFS=$'\n'
    local -a toks
    local -a args

    serial="$1"
    file="$2"

    if [ "$serial" != "none" ]; then
        args=(-s $serial)
    fi

    toks=( ${toks[@]-} $(
        command adb ${args[@]} shell ls -dF ${file}"*" '2>' /dev/null 2> /dev/null | tr -d '\r' | {
            while read -r tmp; do
                filetype=${tmp%% *}
                filename=${tmp:${#filetype}+1}
                if [[ ${filetype:${#filetype}-1:1} == d ]]; then
                    printf '%s/\n' "$filename"
                else
                    printf '%s\n' "$filename"
                fi
            done
        }
    ))

    # Since we're probably doing file completion here, don't add a space after.
    if [[ $(type -t compopt) = "builtin" ]]; then
        compopt -o nospace
    fi

    COMPREPLY=( ${COMPREPLY[@]:-} "${toks[@]}" )
}

_adb_util_complete_local_file()
{
    local file xspec i j
    local -a dirs files

    file=$1
    xspec=$2

    # Since we're probably doing file completion here, don't add a space after.
    if [[ $(type -t compopt) = "builtin" ]]; then
        compopt -o plusdirs
        if [[ "${xspec}" == "" ]]; then
            COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
        else
            compopt +o filenames
            COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") )
        fi
    else
        # Work-around for shells with no compopt

        dirs=( $(compgen -d -- "${cur}" ) )

        if [[ "${xspec}" == "" ]]; then
            files=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
        else
            files=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") )
        fi

        COMPREPLY=( $(
            for i in "${files[@]}"; do
                local skip=
                for j in "${dirs[@]}"; do
                    if [[ $i == $j ]]; then
                        skip=1
                        break
                    fi
                done
                [[ -n $skip ]] || printf "%s\n" "$i"
            done
        ))

        COMPREPLY=( ${COMPREPLY[@]:-} $(
            for i in "${dirs[@]}"; do
                printf "%s/\n" "$i"
            done
        ))
    fi
}


if [[ $(type -t compopt) = "builtin" ]]; then
    complete -F _adb adb
else
    complete -o nospace -F _adb adb
fi

Cross Reference: /sdk/bash_completion/adb.bash

以下のようなコンソール出力になります.

「adb」と文字を入力したあとのひとつスペースに注意しながらのです.


~ $ adb <TAB>
-d                 devices            help               pull               shell              usb
-e                 disconnect         install            push               start-server       version
-p                 emu                jdwp               reboot             status-window      
-s                 forward            kill-server        reboot-bootloader  sync               
bugreport          get-serialno       logcat             remount            tcpip              
connect            get-state          lolcat             root               uninstall          


~ $ adb -<TAB>
-d  -e  -p  -s  


~ $ adb -s 
01f9739f4fd1471c     192.168.10.101:5555  


~ $ adb push a.apk /<TAB>
/acct/              /dev/               /init.environ.rc    /mnt/               /sdcard/            /ueventd.rc
/cache/             /etc/               /init.mako.rc       /persist/           /seapp_contexts     /vendor/
/charger            /file_contexts      /init.mako.usb.rc   /proc/              /sepolicy           
/config/            /firmware/          /init.rc            /property_contexts  /storage/           
/d/                 /fstab.mako         /init.superuser.rc  /res/               /sys/               
/data/              /init               /init.trace.rc      /root/              /system/            
/default.prop       /init.cm.rc         /init.usb.rc        /sbin/              /ueventd.mako.rc    

~ $ adb uninstall <TAB>
Display all 217 possibilities? (y or n)
android                                                com.facebook.orca
com.adamrocker.android.input.simeji                    com.facebook.pages.app
com.adobe.flashplayer                                  com.farproc.wifi.analyzer
com.adobe.reader                                       com.gmail.jp.raziko.radiko
com.alensw.PicFolder                                   com.google.android.apps.adm
com.amazon.mp3                                         com.google.android.apps.ads.publisher
com.americanexpress.android.acctsvcs.japan             com.google.android.apps.authenticator2
com.andrew.apollo                                      com.google.android.apps.books
com.android.apps.tag                                   com.google.android.apps.chromecast.app

特に, ローカル/リモートディレクトリの補完が快適です.

そんな bash の 補完(completion)なスクリプトは他にもいろいろ見つかります.

android-completion/android at master · mbrubeck/android-completion · GitHub

metasystem/modules/android/shell/bash-completion.sh at master · garethstockwell/metasystem · GitHub

adb - romannurik-code - Roman's miscellaneous sample code - Google Project Hosting

お試しあれ.


Android Studio で簡単に jar をつくる手順はないのかと

ふと, こんな.

https://twitter.com/malcheese2/status/457027182133387264

Android Studio 最新版 0.5.5 でどうしたらいいのだろうか.

Create a standalone library with Android Studio | Geek Garage

apply plugin: ‘android'

apply plugin: 'android-library’

./gradlew clean
./gradlew aR

aR=assembleRelease

build/libs/ 以下に .aar ファイルが作成される.

このファイルを別プロジェクトの libs/ 以下にコピーして,依存の記述をすればよし.

Referencing a local aar file in Android Studio | Geek Garage

dependencies {
    compile files('libs/mylib.aar')
}

で「aar」とは何なのか.

Building Android applications with Gradle - Tutorial

Gradle supports a format called Android ARchive (AAR) . An AAR is similar to a JAR file, but it can contain resources as well as compiled bytecode. This allows that an AAR file is included similar to a JAR file

.aar ファイルは zip 圧縮されたファイルで以下が含まれている.

/AndroidManifest.xml (mandatory)
/classes.jar (mandatory)
/res/ (mandatory)
/R.txt (mandatory)
/assets/ (optional)
/libs/*.jar (optional)
/jni//*.so (optional)
/proguard.txt (optional)
/lint.jar (optional)

AAR Format - Android Tools Project Site

Gradle 本家サイトドキュメントなどを見てると広く深いのですが
Android Studio 関連のそこらの話を含め, 以下が一番わかりやすい.

Library projects - Android Tools Project Site

Gradle Plugin User Guide - Android Tools Project Site

で思うのが, .aar から .jar に変換できないか.

java - How to convert AAR to JAR - Stack Overflow

The AAR file consists of a JAR file and some resource files. Here are the steps to convert:

1. Extract the AAR file using standard zip extract
2. Find the classes.jar file in the extracted files
3. Rename it to your liking and use the wanted jar file in your project

Android Studio 左のツリービューからは見えない.

build_libs

ので, ターミナルから確認する.

~/AndroidStudio/SampleProject/volley/build/libs $ unzip -Z volley.aar
Archive:  volley.aar   80932 bytes   5 files
-rw-r--r--  2.0 unx      460 b- defN 23-Mar-14 22:33 AndroidManifest.xml
-rw-r--r--  2.0 unx    89580 b- defN 23-Mar-14 22:33 classes.jar
drwxr-xr-x  2.0 unx        0 b- defN 23-Mar-14 22:33 assets/
drwxr-xr-x  2.0 unx        0 b- defN 13-Feb-14 13:55 jni/
drwxr-xr-x  2.0 unx        0 b- defN 23-Mar-14 22:33 res/
5 files, 90040 bytes uncompressed, 80440 bytes compressed:  10.7%

.aar ファイルは zip 形式なので展開して class.jar をリネームすればよし, と.


AndroidStudio や Gradle ネタも掲載 オライリー「実践 Android Developer Tools」

和訳版がリリースするらしいです.

Android Developer Tools Essentials - O'Reilly MediaO_Reilly_Japan_-_実践_Android_Developer_Tools

O'Reilly Japan - 実践 Android Developer Tools

原書はこちら.

Android_Developer_Tools_Essentials - O_Reilly_Media

Android Developer Tools Essentials - O'Reilly Media

Android Studio や Gradle のネタもあるらしいです.

6章 Android Studioによる開発
    6.1 Android Studioをインストールする
        6.1.1 Android SDKの導入
        6.1.2 プロジェクトのデフォルトの位置
    6.2 Android Studio IDEの解剖
        6.2.1 パネル
        6.2.2 ツールバー
        6.2.3 Android Studioの便利なコマンド
        6.2.4 ナビゲーション
    6.3 Androidプロジェクトの新しい構造
        6.3.1 新しいファイル構造へのツアー
        6.3.2 Androidプロジェクトを実行、デバッグする
    6.4 新しいAndroidコンポーネントを作る
    6.5 レイアウトデザイナとレイアウトプレビュー
        6.5.1 レイアウトデザイナ
        6.5.2 レイアウトプレビュー
    6.6 APKを生成する
    6.7 MavenやGradleとのやり取り
        6.7.1 Mavenを操作する
        6.7.2 Gradleを操作する
    6.8 VCSとの統合
    6.9 EclipseからAndroid Studioに移行するには
    6.1 0 Android Studioのちょっとしたテクニック
        6.10.1 リファクタリングとコード生成
        6.10.2 その他のショートカット
    9.5 Gradleベースのビルドツール
        9.5.1 Gradleをインストールする
        9.5.2 複数のビルドバリエーションを作る
        9.5.3 ビルドファイル
        9.5.4 ビルドタスク
        9.5.5 EclipseからGradle buildを実行する
    9.6 Mavenツールを使う

和訳版は, 2014年4月23日のリリース.

原書が 2013年8月のリリース.

そんなに古くもないので, 予約しておきました.

英語が理解できる人は, 安く早く購入できるのでいいですよね.