1. Android システムの隠しクラスとメソッド
Android のソース コードを読むと、外部アプリケーションからアクセスできない @UnsupportedAppUsage の注釈が付けられたメソッドが多数見つかります。
たとえば、Android の PackageParser クラス、このクラスは android.content.pm パッケージの下にあります。
このクラスは非表示 (@hide) であり、SDK への外部呼び出しを提供しないため、直接インスタンス化できないことがわかります。
このクラスには parsePackageLite 静的メソッドがあります。
このメソッドには @UnsupportedAppUsage の注釈が付けられており、メソッドが呼び出すユーザー アプリをサポートしていないことを示します。
2. システムの隠しクラスとメソッドを呼び出す
①反省による
プライベート void testReflect() {
試す {
Class<?> cls=Class.forName( "android.content.pm.PackageParser");
メソッド[] メソッド=cls.getMethods();
for (int i = 0; i <methods.length; i++) {
Log.i("RR",methods[i].getName());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
ログからこのメソッドが取得できることがわかります。
② システムのクラスを宣言し、空の実装をして例外をスローする
クラスを見ると、次のようなコードがよく見られますが、これがコンパイルされて渡され、最終的に呼び出されるときに、最終的なシステム実装クラスが見つかります。
システムの書き方を参考にしてみてください
作成されたクラスがシステムと同じパッケージ名を持つようにするには、その中で参照する必要がある他のクラスも宣言して記述する必要があります。
PackageParser.java:
パッケージ android.content.pm;
java.io.ファイルをインポートします。
java.security.cert.Certificateをインポートします。
java.util.Listをインポートします。
パブリック クラス PackageParser {
public static PackageLite parsePackageLite(File packageFile, int flags) throws PackageParserException {
throw new RuntimeException("Stub!");
}
パブリック静的クラス PackageLite {
public Final String パッケージ名;
...すべての属性が直接コピーされます
public PackageLite(String codePath, ApkLite BaseApk, String[] SplitNames, String[] SplitCodePaths, int[] SplitRevisionCodes) {
this.packageName = BaseApk.packageName;
...すべての属性割り当てが直接コピーされます
}
public List<String> getAllCodePaths() {
throw new RuntimeException("Stub!");
}
}
パブリック静的クラス ApkLite {
パブリック最終文字列コードパス;
...すべての属性がコピーされます
public ApkLite(String codePath, String packageName, String SplitName, int versionCode, intreviationCode, int installLocation, List<VerifierInfo> 検証者、Signature[] 署名、Certificate[][] 証明書、boolean coreApp、boolean multiArch、boolean use32bitAbi、boolean extractNativeLibs ) {
throw new RuntimeException("Stub!");
}
}
public static class PackageParserException extends Exception {
パブリック最終整数エラー;
public PackageParserException(int error, StringdetailMessage) {
スーパー(詳細メッセージ);
throw new RuntimeException("Stub!");
}
public PackageParserException(int error, StringdetailMessage, Throwable throwable) {
super(detailMessage, throwable);
throw new RuntimeException("Stub!");
}
}
}
ご覧のとおり、実装部分は throw new RuntimeException("Stub!"); に置き換えられています。
注: すべての属性を書き込む必要があります (UnsupportedAppUsage アノテーションがある場合はアノテーションを削除します)。ソース コードをコピーして、実装を throw new RuntimeException("Stub!"); に置き換えることができます。
VerifierInfo.java:
パッケージ android.content.pm;
android.os.Parcel をインポートします。
android.os.Parcelable をインポートします。
java.security.PublicKeyをインポートします。
パブリック クラス VerifierInfo は Parcelable {を実装します
public Final String パッケージ名;
公開最終公開鍵 publicKey;
public VerifierInfo(String packageName, PublicKey publicKey) {
throw new RuntimeException("Stub!");
}
private VerifierInfo(パーセル ソース) {
throw new RuntimeException("Stub!");
}
@オーバーライド
public int descriptionContents() {
throw new RuntimeException("Stub!");
}
@オーバーライド
public void writeToParcel(Parcel dest, int flags) {
throw new RuntimeException("Stub!");
}
public static Final Parcelable.Creator<VerifierInfo> CREATOR = new Parcelable.Creator<VerifierInfo>() {
public VerifierInfo createFromParcel( パーセル ソース) {
throw new RuntimeException("Stub!");
}
public VerifierInfo[] newArray(int size) {
throw new RuntimeException("Stub!");
}
};
}
その後、アプリ内で隠しメソッドを呼び出すことができます。
private void testRuntimeExp() {
ファイル file=new File(Environment.getExternalStorageDirectory().getPath()+"/mm/app-debug.apk");
if (!file.exists()) {
Toast.makeText(this, "ファイルが存在しません", Toast.LENGTH_SHORT).show();
戻る;
}
試す {
PackageParser.PackageLite packageLite= PackageParser.parsePackageLite(file,0);
Log.i("RR","パッケージ名:" + packageLite.パッケージ名);
Log.i("RR","versionCode:" + packageLite.versionCode);
Log.i("RR","installLocation:" + packageLite.installLocation);
Log.i("RR","codePath:" + packageLite.codePath);
Log.i("RR","baseCodePath:" + packageLite.baseCodePath);
Log.i("RR","coreApp:" + packageLite.coreApp);
文字列 s="";
} catch (PackageParser.PackageParserException e) {
e.printStackTrace();
}
}
結果:
結果が正しいことを確認すると、情報が得られます。