非SDKインターフェースを使用しているか調べる方法

AndroidアプリのOSアップデート対応をした際に、非SDKインターフェースについて疑問に思ったことが多かったので、調べた情報をまとめました。

## 非SDKインターフェースとは
非SDKインターフェースとは、Googleから公式に公開されていないクラスやメソッドのこと。（hidden API や 内部API と呼ばれたりする）

反対に通常のSDKインターフェースは、GoogleがAndroidアプリ開発者向けに、正式に公開・サポートしているクラスやメソッドのこと。
ContextやActivity, Viewなどが挙げられます。

## 非SDKインターフェースはなぜ制限されるのか

公式にサポートされていないため、急に使えなくなる可能性があります。
OSアップデートによりアプリがクラッシュしたり、不具合が起きたりする可能性を下げるために制限されます。



Android 9（API 28）以降から制限されるようになっており、制限には以下の種類があるようです。

| コードタグ | 説明 |
|:-----------|:------------|
| blocked / blacklist | クラッシュまたは無視される |
| max-target-x / greylist-max-x    | API レベルごとにエラーや例外がスローされる |
| unsupported / greylist       | 今は制限されておらず、今後される可能性あり |


## 非SDKインタフェースを使用しているかの確認

公式でもいくつか方法が挙げられていますが、私は以下の方法を試しました。

### 1. ログを確認する
デバック状態でアプリを動かし、Logcatでログを確認しました。
画面の遷移やアクションなど、すべての動作を網羅するようにアプリを動かします。
その際、非SDKインタフェースを使用していた場合は以下のようなログが出力されます。
````
W  Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (greylist, reflection, allowed)
````
Accessing hidden methodの他に、Accessing hidden field、Accessing hidden constructor、Accessing hidden classなどもあります。


### 2. veridexで確認する
veridexはapkファイルの静的解析ツールです。
JNI を介した呼び出しは検出できないなど一部制約はありますが、調査の１つとして取り入れても良いと思います。

手順は以下のとおりです。
1. [ここ](https://android.googlesource.com/platform/prebuilts/runtime/+archive/main/appcompat.tar.gz)からveridexツールをダウンロード
1. .tar.gzファイルがダウンロードされるので、ダブルクリックで解凍
1. 手順2で解凍したフォルダの中にあるveridex-mac.zipを解凍
1. ターミナルでveridex-macのフォルダに移動して、以下コマンドを実行
```
$ ./appcompat.sh --dex-file=apkファイルのルートパス
```
以下はデスクトップにapp-debug.apkという名前のapkファイルがある例です。
```
$ ./appcompat.sh --dex-file=/Users/自身のユーザー名/Desktop/app-debug.apk
```
:::note warn
“veridex”が開けないなどのエラーダイアログが表示される場合は、macのシステム設定 > プライバシーとセキュリティ > セキュリティの項目で「AppStore」にチェックをした状態であれば、「このまま許可」というボタンが表示されます。
:::

コマンド実行がうまくいくと、以下のようなものが出力されます。
```
veridex-mac % ./appcompat.sh --dex-file=/Users/自身のユーザー名/Desktop/app-debug.apk
NOTE: appcompat.sh is still under development. It can report
API uses that do not execute at runtime, and reflection uses
that do not exist. It can also miss on reflection uses.
#1: Linking blocked Landroid/icu/number/FormattedNumber;->getOutputUnit()Landroid/icu/util/MeasureUnit; use(s):
       Landroidx/core/text/util/LocalePreferences$Api33Impl;->getResolvedTemperatureUnit(Ljava/util/Locale;)Ljava/lang/String;

#2: Linking blocked Landroid/icu/text/DateFormat$HourCycle;->values()[Landroid/icu/text/DateFormat$HourCycle; use(s):
       Landroidx/core/text/util/LocalePreferences$1;-><clinit>()V
       
~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~

#83: Reflection unsupported Lsun/misc/Unsafe;->allocateInstance use(s):
       Lcom/google/gson/internal/UnsafeAllocator;->create()Lcom/google/gson/internal/UnsafeAllocator;

#84: Reflection unsupported Lsun/misc/Unsafe;->theUnsafe use(s):
       Lcom/google/gson/internal/UnsafeAllocator;->create()Lcom/google/gson/internal/UnsafeAllocator;

84 hidden API(s) used: 26 linked against, 58 through reflection
	56 in unsupported
	10 in blocked
	6 in max-target-o
	10 in max-target-p
	2 in max-target-q
	0 in max-target-r
To run an analysis that can give more reflection accesses, 
but could include false positives, pass the --imprecise flag. 
```

## あとがき
警告に対する対処法はまた別途まとめようと思います。
夜に殴り書きしたので、時間がある時に少しずつメンテします。










参考：https://developer.android.com/guide/app-compatibility/restrictions-non-sdk-interfaces?hl=ja