Android studio无法直接使用系统隐藏类、变量、接口导致的编译错误的 解决经验

一、错误常见现象:

直接使用@UnsupportedAppUsage注释的变量、@SystemApi的接口,import 系统隐藏类@hide(不希望外部apk直接使用或者类内大多是前两者变量和接口)如import android.os.ServiceManager,所有使用这些代码的地方直接飘红,因为这些注解的函数、类、变量是不编译进谷歌提供的sdk里的,直接使用的话编译器检查自然过不了。

二、解决办法:

1. 通常谷歌合作厂商为了方便会搞一个jar包出来不同于直接自动download的androidsdk中的jar,并进行替换,其中内容不同于原内容,也消除了隐藏变量接口的注解,以便直接使用。

(补充解释jar 是java的归档格式,是一个程序集(微软体系都这么叫),展开基本全是class文件。sdk 不限语言,不限平台,这个范围很广。

操作步骤:

 

       将提供的android.jar对路径下android.jar替换,原jar重名为bak即可。androidstudio会检测到并自动重新index目录到项目cache中,就不再飘红可以直接使用了。(有时厂商还有其独特的framework-res.apk也是要直接放到这个目录下的,以方便apk直接调用其在框架创建的品牌前缀的系统类)(如果还有其他的jar包使用,不能放在这里,要放在对应项目的中lib文件夹中,并在gradle中的dependencies中添加 "implementation files('libs\\abcdefg.jar')" 或在androidstudio界面中右键此包选择"将此包作为库文件使用"等类似字眼)

       如果可以自己编译系统源码的话,通过make framework-minus-apex -j16,然后拿此目录的jar包:out/target/common/obj/JAVA_LIBRARIES/framework-minus-apex_intermediates/classes.jar即可。

 

2. 使用反射、假接口和假的aidl进行模拟访问骗过apk编译就OK了,根据虚拟机原理apk将使用系统已经加载好的这些类,只要假接口和aidl的包路径和系统里的一样,且不要在apk配置中开启代码混淆,就可以顺利访问到系统内的实际功能代码。

    操作步骤:

举例解释:

 

    public void disableNavigation(){
        try {
            //STATUS_BAR_SERVICE是系统api,不暴露给apk用,拿出来放到apk类变量中或者反射用都可以,这里拿出来了。DISABLE_NAVIGATION是View.java中的同理被我拿出来了。
            //ServiceManager的getService是注解不暴露给外部apk用的,我们这里通过反射调用了,接收它用了apk里我们自己写的aidl假接口
            Method method = null;
            method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
            IBinder binder = (IBinder) method.invoke(null, STATUS_BAR_SERVICE);
            if (binder != null) {
                IStatusBarService mISs = IStatusBarService.Stub.asInterface(binder);
                mISs.disable(DISABLE_NAVIGATION, new Binder(), getApplicationContext().getPackageName());
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
            //原代码
            //        IStatusBarService mISs = IStatusBarService.Stub.asInterface(ServiceManager.getService(STATUS_BAR_SERVICE));
            //        try {
            //            mISs.disable(StatusBarManager.DISABLE_NAVIGATION, new Binder(), getApplicationContext().getPackageName());
            //        } catch (RemoteException e) {
            //            e.printStackTrace();
            //        }
    }

 

        只将需要的接口写到apk的aidl中即可。

        但是注意,如果调用的是hide-api,可能会报在对应类或jar包中找不到相应函数(具体什么样的函数无法被反射到很难从注解角度下结论,谷歌可能是有一份api暴露名单,具体问题需要具体验证),那是因为你的应用不是系统应用或者没有系统签名,应用如果无法改变,

就要在/frameworks/base/core/java/android/content/pm/ApplicationInfo.java的isAllowedToUseHiddenApis函数里加应用白名单。

 

3.同理,使用假java类也可以解决一些类似的问题:

 

 (如果你觉得有用的话可以关注下博主~欢迎评论区讨论~请注明转载链接~)

 

posted @ 2022-05-17 16:48  小汀  阅读(5090)  评论(0编辑  收藏  举报