Android Projectの詳細を取得する

📅 2016/07/12

Android gradle Scala

buildフォルダを探索して依存ライブラリやクラス一覧を取得するコードを書いていたのですがbuildVariants周りがややこしいためAndroid Projectの構造を取得するためのサンプルコードを書きました。 Android Projectの構造はbuilder-mode-2.1.2.jarの中にあるAndroidProjectが保持しています。 GradleConnectorAndriodProjectクラスを指定するとビルド生成物の出力先や依存ライブラリやsigningConfigなどのbuild.gradleに書かれている情報が取得できます。 詳しくはandroid-project-connect-exampleAndroidGradleConnectorSpec.scalaを参照してください。

Memo: A URL list of Android related repositories

📅 2016/07/07

Android

Androidのtool寄りのコードを書くようになったのでメモ。 git cloneしたらめっちゃHDD容量持っていかれる。

ちなみにandroid.googlesource.co以下のrepositoryリストは以下のURLから取得可能です。 https://android.googlesource.com/?format=TEXT tagと日付を表示するワンライナー
git tag -l | while read -r tag ; do COMMIT_HASH=$(git rev-list -1 $tag) && GIT_COMMITTER_DATE="$(git show $COMMIT_HASH --format=%aD | head -1)" && echo $tag $GIT_COMMITTER_DATE; done

参考

http://stackoverflow.com/a/25939259/2306073

CircleCIを使ってAndroidのテストを実行する

📅 2015/11/18

Android gradle CircleCI

プライベートなリポジトリはdroneioでコンテナ作ってビルドから通知までやっていました。 GitHubのリポジトリは折角なのでCircleCIで回すことにしました。 その時に罠があったので紹介します。

cache_directoriesの罠

以下のように記載してました。
dependencies:
  cache_directories:
    - $ANDROID_HOME/platforms/android-23
    - $ANDROID_HOME/build-tools/23.0.1
    - $ANDROID_HOME/extras/android
    - $ANDROID_HOME/extras/google

$ANDROID_HOME/usr/local/android-sdk-linuxと展開されると期待したら、以下のようなwaringが出ていました。

Warning: circle.yml specified cache directories: /home/ubuntu/android-ci/$ANDROID_HOME/build-tools/23.0.1, /home/ubuntu/android-ci/$ANDROID_HOME/extras/google, /home/ubuntu/android-ci/$ANDROID_HOME/platforms/android-23, /home/ubuntu/android-ci/$ANDROID_HOME/extras/android but they don't exist

/から始まるものでないと絶対パスとして扱われない…?罠過ぎる。 変数展開を期待してダブルクォーテーションで囲ってみたが相対パス扱いのままだったのでベタ書きすることにしました。 またandroid list sdk -u -a -eでupdate sdkに使うパッケージ名を出すことができます。 GitHub android-ci

参考

com.android.ide.common.process.ProcessException

📅 2015/08/06

Android Retrolambda

見覚えのないエラーが出たので何かと思ったらretrolambdaの記述が足りてなかった…。

Error:Execution failed for task ':rx-okhttp-sample:dexDebug'.
> com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command '/Library/Java/JavaVirtualMachines/jdk1.8.0_51.jdk/Contents/Home/bin/java'' finished with non-zero exit value 1

足りていなかったのは以下の記述。

apply plugin: 'me.tatarka.retrolambda'

AndroidのテストをJUnit4に対応する

📅 2015/07/22

Android Testing

AndroidをJUnit4を使ったテストに変更します。 今までのテストは以下の通りにAndroidTestCaseを使っていました。

public class HogeTest extends AndroidTestCase {
    public void testHige() {
        Hige hige = createHige(getContext());
        assertThat("check hige", hige, is(notNullValue()))
    }
}

Developers - Building Instrumented Unit Testsの通りにbuild.gradleを設定し、上記のテストケースを書き換えます。

@RunWith(AndroidJUnit4.class)
public class HogeTest {
    @Test
    public void hige() {
        Hige hige = createHige(InstrumentationRegistry.getContext());
        assertThat("check hige", hige, is(notNullValue()))
    }
}

変わった点は、継承がなくなったためContextの取得方法が違う点といくつかのアノテーションの追加になります。 必要であればInstrumentationRegistryからContextをするようにとAndroidJUnitRunnerのドキュメントに記述されていました。

参考

AndroidのToolbarにスタイルを適用する

📅 2015/07/10

Android Design

ActionBarを無効化

NoActionBarを継承したスタイルを作り、applicationのthemeに設定する。

Androidmanifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="epy0n0ff.com.toolbar"
    >
  <application
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:theme="@style/AppTheme"
      >
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        >
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
      </intent-filter>
    </activity>
  </application>
</manifest>

styles.xml

<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
  </style>

Toolbarの色を変更する

NoActionBarを継承したスタイルを作る。スタイルを適用しただけではだめなので、利用するActivityで必ず先にsetSupportActionBar(toolbar)しておく。

  • android:backgroundはToolbarの背景色
  • android:textColorPrimaryはToolbarのタイトルテキストの色
  • actionMenuTextColorはToolbarに設定したメニューのテキストの色

styles.xml

<style name="ToolbarTheme" parent="Theme.AppCompat.NoActionBar">
    <!-- setSupportActionbar()で設定しないと適用されない -->
    <item name="android:background">#ffffff</item>
    <item name="android:textColorPrimary">#0000ff</item>
    <item name="actionMenuTextColor">#00ff00</item>
  </style>

プレビュー

こんな感じになります。

[メモ]動画ファイルのContentResolverの戻り値

📅 2015/06/05

Android
動画をギャラリーから開くIntent
new Intent(Intent.ACTION_PICK, MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
onActivityResultで受けたIntentからContentResolverへ問い合わせ
Cursor cursor = getContentResolver().query(data.getData(), null, null, null, null);
cursor.moveToFirst();
for(int i=0; i< cursor.getColumnCount(); i++) {
  Log.d("movie", cursor.getColumnName(i) );
}
結果
_id
_data
_display_name
_size
mime_type
date_added
date_modified
title
duration
artist
album
resolution
description
isprivate
tags
category
language
mini_thumb_data
latitude
longitude
datetaken
mini_thumb_magic
bucket_id
bucket_display_name
bookmark
width
height

AndroidのmanifestPlaceholdersの使いどころ

📅 2015/05/22

Android

build.gradleのbuildTypesとproductFlavors内でmanifestPlaceholdersと変数展開について軽くまとめてみる。 今のところ使った場面は以下の4つです。

  • GCMのPermission
  • GCMのIntentFilter
  • AndroidManifestでSearchRecentSuggestionsProviderの定義
  • android:schemeのホスト名

build.gradleを以下のように設定している場合についてそれぞれ説明します。

build.gradle

android {
...
  buildTypes {
    release {
      manifestPlaceholders = [hostName: "epy0n0ff.com"]
      minifyEnabled false
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    develop {
      debuggable true
      signingConfig signingConfigs.debug
      manifestPlaceholders = [hostName: "dev.epy0n0ff.com"]
      applicationIdSuffix '.develop'
    }
    local {
      debuggable true
      signingConfig signingConfigs.debug
      manifestPlaceholders = [hostName: "local.epy0n0ff.com"]
      applicationIdSuffix '.local'
    }
    debug {
      debuggable true
      signingConfig signingConfigs.debug
      manifestPlaceholders = [hostName: "dev.epy0n0ff.com"]
      applicationIdSuffix '.debug'
    }
  }
...
}

GCMのPermission

GCMのPermission要素にはapplicationIdを含みます。 buildTypes毎にAndroidManiefst.xmlを用意してもいいのですが、事故を減らすために main/AndroidManifest.xmlを以下の用に変更します。

AndroidManifest.xml(適用前)

<permission android:name="com.epy0n0ff.develop.permission.C2D_MESSAGE"
      android:protectionLevel="signature"/>
  <uses-permission android:name="com.epy0n0ff.develop.permission.C2D_MESSAGE"/>
</code></pre>
AndroidManifest.xml(適用後)
<pre><code>
<permission android:name="${applicationId}.permission.C2D_MESSAGE"
      android:protectionLevel="signature"/>
  <uses-permission android:name="com.epy0n0ff.develop.permission.C2D_MESSAGE"/>

GCMのIntentFilter

GCMの設定には前項以外にもIntentFilterにapplicationIdが使用されています。 ここもapplicationIdの変数を使うように変更します。 AndroidManifest.xml(適用前)

    <receiver
        android:name="com.epy0n0ff.GCMReceiver"
        android:permission="com.google.android.c2dm.permission.SEND"
        >
      <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
        <action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
        <category android:name="com.epy0n0ff.develop"/>
      </intent-filter>
    </receiver>

AndroidManifest.xml(適用後)

    <receiver
        android:name="com.epy0n0ff.GCMReceiver"
        android:permission="com.google.android.c2dm.permission.SEND"
        >
      <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
        <action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
        <category android:name="${applicationId}"/>
      </intent-filter>
    </receiver>

AndroidManifestでSearchRecentSuggestionsProviderの定義

見落としがちというか気づきにくいのがSearchRecentSuggestionsProviderの定義です。 Logcatで見ていると以下のようなエラーが出るので修正します。 /com.epy0n0ff.develop E/ActivityThread﹕ Failed to find provider info for com.epy0n0ff.content.provider.search

AndroidManifest.xml(適用前)

<provider
        android:name=".content.provider.RecentSearchSuggestionProvider"
        android:authorities="com.epy0n0ff.content.provider.search"
        android:exported="false"
        />

AndroidManifest.xml(適用後)

<provider
        android:name=".content.provider.RecentSearchSuggestionProvider"
        android:authorities="${applicationId}.content.provider.search"
        android:exported="false"
        />

android:schemeのホスト名

ここでやっとmanifestPlaceholdersの登場です。 manifestPlaceholdersはkey-valueのmapなので${key}と書くとそこにvalueが展開されます。

AndroidManifest.xml(適用前)

   <activity
        android:name=".view.activity.UrlInterpreterActivity"
        android:launchMode="singleTask"
        android:noHistory="true">
      <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data
            android:host="develop.epy0n0ff.com"
            android:pathPattern="/sp/.*"
            android:scheme="http"/>
    </activity>

AndroidManifest.xml(適用後)

    <activity
        android:name=".view.activity.UrlInterpreterActivity"
        android:launchMode="singleTask"
        android:noHistory="true">
      <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data
            android:host="${hostName}"
            android:pathPattern="/sp/.*"
            android:scheme="http"/>
    </activity>

参考

apktoolでエラー

📅 2015/05/08

Android smali

apktoolでデコンパイルしようと以下の様なエラーが出た。

apktool d hoge.apk
...
W: Could not decode attr value, using undecoded value instead: ns=android, name=touchscreenBlocksFocus, value=0xffffffff
...

どうやらframework.apkが古いようなのでnexus5から引っ張ってきて入れ替える。

adb pull /system/framework/framework-res.apk
apktool if framework-res.apk

これで無事デコンパイルできるようになった。

参考

[電話] apktoolでapkを弄り回す日々。そのいち