1.Android系统隐藏的类和方法
阅读Android源码时,会发现很多被@UnsupportedAppUsage注解的方法,这些方法不能被外部应用访问。
比如Android中的PackageParser类,这个类是在android.content.pm包下面:
可以看到这个类是隐藏的(@hide),不对外提供sdk的调用,所以不能直接去实例化。
这个类里面有一个parsePackageLite静态方法:
这个方法有@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();
}
}
通过log可以看到,是可以获得到这个方法的。
②声明系统的类,空实现,抛异常
在查看类的时候,经常可以看到下面的代码,这个是编译通过,在最终调用的时候,会去找最终的系统实现类。
于是就参照系统的写法来试试
要保证创建的类和系统的包名一样,里面需要引用的其他类也要声明,写上。
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();
}
}
结果:
看到结果是正确的,可以获得信息。