Android 调用系统隐藏的类和方法

  • Post author:
  • Post category:其他


1.Android系统隐藏的类和方法

阅读Android源码时,会发现很多被@UnsupportedAppUsage注解的方法,这些方法不能被外部应用访问。

比如Android中的PackageParser类,这个类是在android.content.pm包下面:

0d41f917553b4ea0a837b6e1cb012067.png

可以看到这个类是隐藏的(@hide),不对外提供sdk的调用,所以不能直接去实例化。

这个类里面有一个parsePackageLite静态方法:

c70522b8cf094f05ba6f791955c9e2e6.png

这个方法有@UnsupportedAppUsage注解,表示该方法不支持用户app去调用。

2.调用系统隐藏的类和方法

①通过反射

private void testReflect() {

try {

Class<?> cls=Class.forName( “android.content.pm.PackageParser”);

Method[] methods=cls.getMethods();

for (int i = 0; i < methods.length; i++) {

Log.i(“RR”,methods[i].getName());

}

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

0993a440524a4d09a276a919e9f49905.png
通过log可以看到,是可以获得到这个方法的。

②声明系统的类,空实现,抛异常

在查看类的时候,经常可以看到下面的代码,这个是编译通过,在最终调用的时候,会去找最终的系统实现类。

cf5bc56f0de0432abb53999ac4e26678.png

于是就参照系统的写法来试试

c6523821ba18476baec4d7b23346b893.png

要保证创建的类和系统的包名一样,里面需要引用的其他类也要声明,写上。

PackageParser.java:

package android.content.pm;

import java.io.File;

import java.security.cert.Certificate;

import java.util.List;

public class PackageParser {

public static PackageLite parsePackageLite(File packageFile, int flags) throws PackageParserException {


throw new RuntimeException(“Stub!”);

}

public static class PackageLite {

public final String packageName;

……所有属性直接拷过来

public PackageLite(String codePath, ApkLite baseApk, String[] splitNames, String[] splitCodePaths, int[] splitRevisionCodes) {

this.packageName = baseApk.packageName;

……所有属性赋值直接拷过来

}

public List<String> getAllCodePaths() {


throw new RuntimeException(“Stub!”);

}

}

public static class ApkLite {

public final String codePath;

……所有属性拷过来

public ApkLite(String codePath, String packageName, String splitName, int versionCode, int revisionCode, int installLocation, List<VerifierInfo> verifiers, Signature[] signatures, Certificate[][] certificates, boolean coreApp, boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs) {


throw new RuntimeException(“Stub!”);

}

}

public static class PackageParserException extends Exception {

public final int error;

public PackageParserException(int error, String detailMessage) {

super(detailMessage);


throw new RuntimeException(“Stub!”);

}

public PackageParserException(int error, String detailMessage, Throwable throwable) {

super(detailMessage, throwable);


throw new RuntimeException(“Stub!”);

}

}

}

可以看到,实现的部分都用throw new RuntimeException(“Stub!”); 这个代替了。

注意:属性要全部写上(有UnsupportedAppUsage注解的,把注解删掉),可以把源码拷贝过来,然后把实现替代为throw new RuntimeException(“Stub!”);

VerifierInfo.java:

package android.content.pm;

import android.os.Parcel;

import android.os.Parcelable;

import java.security.PublicKey;

public class VerifierInfo implements Parcelable {

public final String packageName;

public final PublicKey publicKey;

public VerifierInfo(String packageName, PublicKey publicKey) {


throw new RuntimeException(“Stub!”);

}

private VerifierInfo(Parcel source) {


throw new RuntimeException(“Stub!”);

}

@Override

public int describeContents() {


throw new RuntimeException(“Stub!”);

}

@Override

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( Parcel source) {


throw new RuntimeException(“Stub!”);

}

public VerifierInfo[] newArray(int size) {


throw new RuntimeException(“Stub!”);

}

};

}

接下来就可以在app中调用该隐藏方法了:

private void testRuntimeExp() {

File file=new File( Environment.getExternalStorageDirectory().getPath()+”/mm/app-debug.apk”);

if (!file.exists()) {

Toast.makeText(this, “file is not exist”, Toast.LENGTH_SHORT).show();

return;

}

try {

PackageParser.PackageLite packageLite= PackageParser.parsePackageLite(file,0);

Log.i(“RR”,”packageName:” + packageLite.packageName);

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);

String s=””;

} catch (PackageParser.PackageParserExc eption e) {

e.printStackTrace();

}

}

结果:

9eb01c4a2e68489eaada4bf516c5953e.png

看到结果是正确的,可以获得信息。



版权声明:本文为zenmela2011原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。