Android Framework中调用由java编译成的jar接口

文章目录

把java代码编译成jar

1. 创建目录

bash 复制代码
创建一个临时项目目录
mkdir EdgeGesturePrivate
cd EdgeGesturePrivate

# 要根据包名来创建文件夹
mkdir src/com/android/server/policy/

# 然后在此目录下创建EdgeGestureArrowManager.java

2. 创建java代码

java源码

java 复制代码
package com.android.server.policy;

public class EdgeGestureArrowManager {
    public EdgeGestureArrowManager(Context context) {
    }

    public void systemReady() {
    }

    public void onSwipeFromLeftStart(float initialY) {
    }

    public void onSwipeFromLeftCancel() {
    }

    public void onSwipeFromLeftComplete() {
    }
}

3. 从AOSP安卓源码中找到framework.jar

Android8一般是这个文件:

text 复制代码
./out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar

把它拷贝到上面创建的目录EdgeGesturePrivate中的libs目录下,如果没有这个jar后面手动编译java会报错。

4. 编译生成jar

手动编译

注意此方法只是做个简单示范,实际后面操作起来会比较复杂,不建议使用(后面会介绍如何在AOSP androd sdk源码中编译,且推荐用这种方法)

创建编译脚本cc.sh

shell 复制代码
# 编译为JAR
javac -cp "libs/classes.jar" \
      -source 1.8 -target 1.8 \
      -d ./classes \
      src/com/android/server/policy/EdgeGestureArrowManager.java

# 打包
jar cvf EdgeGestureArrowManager.jar -C classes

执行后,不报错情况下会生成EdgeGestureArrowManager.jar。

执行以下指令,验证生成的jar是否正常:

bash 复制代码
jar tf EdgeGestureArrowManager.jar

正常会输出类似如下的内容:

text 复制代码
META-INF/
META-INF/MANIFEST.MF
com/
com/android/
.....

AOSP编译(推荐)

此方法能应对各种报错,推荐用这种方法,具体使用后面会详细说明,这只省略。

初步方案如下

1. 想法

想在frameworks/base/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java中调用jar中的函数,

可以直接在frameworks/base/services/core/下修改,把jar集成到安卓代码中。

Android SDK中

text 复制代码
frameworks/base/libs
├── EdgeGestureArrowManager/  # 新建这个目录存放闭源JAR
    └── EdgeGestureArrowManager.jar

frameworks/base/services/core/
├── Android.mk                    # 修改这个文件
└── java/com/android/server/policy/
    └── SystemGesturesPointerEventListener.java  # 在这里面调用jar中的函数

2. 创建libs目录并放入JAR

bash 复制代码
# 1. 创建libs目录
mkdir -p frameworks/base/libs/EdgeGestureArrowManager

# 2. 复制你的JAR文件
cp /path/to/EdgeGestureArrowManager.jar frameworks/base/libs/EdgeGestureArrowManager/

3. 反射调用

EdgeGestureHelper.java封装了对jar的反射调用接口

java 复制代码
package com.android.server.policy;

import android.content.Context;
import android.util.Slog;
import android.util.Log;

/**
 * 边缘手势帮助类 - 直接反射调用闭源代码
 */
public class EdgeGestureHelper {
    private static final String TAG = "EdgeGestureHelper";
    private static final String CLASS_NAME = "com.android.server.policy.EdgeGestureArrowManager";

    private Object mManagerInstance;
    private boolean mAvailable = false;

    public EdgeGestureHelper(Context context) {
        try {
            Class<?> clazz = Class.forName(CLASS_NAME);
            mManagerInstance = clazz.getConstructor(Context.class).newInstance(context);
            mAvailable = true;
            Slog.i(TAG, "EdgeGesture loaded");
            Log.d(TAG, "----------EdgeGesture loaded");
        } catch (Exception e) {
            Slog.w(TAG, "EdgeGesture not available: " + e.getMessage());
        }
    }

    public void systemReady() {
        Log.d(TAG, "----------systemReady");
        callMethod("systemReady");
    }

    public void onSwipeFromLeftStart(float initialY) {
        Log.d(TAG, "------------onSwipeFromLeftStart");
        callMethod("onSwipeFromLeftStart", float.class, initialY);
    }

    public void onSwipeFromLeftCancel() {
        Log.d(TAG, "-------------onSwipeFromLeftCancel");
        callMethod("onSwipeFromLeftCancel");
    }

    public void onSwipeFromLeftComplete() {
        Log.d(TAG, "---------onSwipeFromLeftComplete");
        callMethod("onSwipeFromLeftComplete");
    }

    private void callMethod(String methodName, Object... args) {
        if (!mAvailable || mManagerInstance == null) return;

        try {
            Class<?>[] paramTypes = new Class<?>[args.length];
            Object[] actualArgs = new Object[args.length];
            
            for (int i = 0; i < args.length; i++) {
                Object arg = args[i];
                actualArgs[i] = arg;
                
                // 获取实际参数类型
                if (arg instanceof Integer) {
                    paramTypes[i] = int.class;
                } else if (arg instanceof Float) {
                    paramTypes[i] = float.class;
                } else if (arg instanceof Double) {
                    paramTypes[i] = double.class;
                } else if (arg instanceof Boolean) {
                    paramTypes[i] = boolean.class;
                } else if (arg instanceof Long) {
                    paramTypes[i] = long.class;
                } else if (arg instanceof Short) {
                    paramTypes[i] = short.class;
                } else if (arg instanceof Byte) {
                    paramTypes[i] = byte.class;
                } else if (arg instanceof Character) {
                    paramTypes[i] = char.class;
                } else {
                    // 对于非基本类型,使用实际的类
                    paramTypes[i] = arg.getClass();
                }
            }

            mManagerInstance.getClass()
                .getMethod(methodName, paramTypes)
                .invoke(mManagerInstance, actualArgs);

        } catch (Exception e) {
            Slog.e(TAG, "Failed to call " + methodName, e);
            Log.e(TAG, "--------Failed to call " + methodName, e);
        }
    }

    // 重载方法,允许显式指定参数类型
    private void callMethod(String methodName, Class<?> paramType, Object arg) {
        if (!mAvailable || mManagerInstance == null) return;

        try {
            mManagerInstance.getClass()
                .getMethod(methodName, paramType)
                .invoke(mManagerInstance, arg);

        } catch (Exception e) {
            Slog.e(TAG, "Failed to call " + methodName, e);
            Log.e(TAG, "--------Failed to call " + methodName, e);
        }
    }

    public boolean isAvailable() {
        return mAvailable;
    }
}

然后在 SystemGesturesPointerEventListener 中就可以通过EdgeGestureHelper调用到jar中的功能了:

java 复制代码
public class SystemGesturesPointerEventListener {
    private EdgeGestureHelper mEdgeHelper;
    
    public SystemGesturesPointerEventListener(Context context) {
        mEdgeHelper = new EdgeGestureHelper(context);
    }
    
    public void onPointerEvent(MotionEvent event) {
        // ... 手势检测逻辑
        
        if (event.getAction() == MotionEvent.ACTION_DOWN && event.getX() < 50) {
            mEdgeHelper.callSwipeFromLeftStart(event.getY());
        }
        
        if (event.getAction() == MotionEvent.ACTION_UP) {
            mEdgeHelper.callSwipeFromLeftComplete();
        }
        
        // 系统就绪时调用
        mEdgeHelper.callSystemReady();
    }
}

4. 修改Android.mk

要在frameworks/base/services/core/子目录中的java去调用我们的jar,所以我们修改frameworks/base/services/core/Android.mk

使用LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES(失败)

makefile 复制代码
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := services.core
LOCAL_SRC_FILES := $(call all-java-files-under,java)

# 使用 LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := EdgeGestureArrowManager:../libs/EdgeGestureArrowManager/EdgeGestureArrowManager.jar

# 其他配置保持原样...
LOCAL_JAVA_LIBRARIES := \
    services.net \
    android.hardware.light-V2.0-java \
    android.hardware.power-V1.0-java \
    android.hardware.tv.cec-V1.0-java \
    android.hidl.manager-V1.0-java

LOCAL_STATIC_JAVA_LIBRARIES += \
    time_zone_distro \
    time_zone_distro_installer \
    android.hidl.base-V1.0-java-static \
    android.hardware.weaver-V1.0-java-static \
    android.hardware.biometrics.fingerprint-V2.1-java-static \
    android.hardware.oemlock-V1.0-java-static \
    android.hardware.tetheroffload.control-V1.0-java-static \
    android.hardware.vibrator-V1.0-java-constants \
    android.hardware.configstore-V1.0-java-static

# 保持其他配置不变...
include $(BUILD_STATIC_JAVA_LIBRARY)

注意,这里如果把

LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := EdgeGestureArrowManager:.../libs/EdgeGestureArrowManager/EdgeGestureArrowManager.jar

改成

LOCAL_STATIC_JAVA_LIBRARIES := EdgeGestureArrowManager:libs/EdgeGestureArrowManager.jar

会报错:

text 复制代码
ninja: error: 'out/target/common/obj/JAVA_LIBRARIES/services.core_intermediates/classes.jar', needed by 'out/target/common/obj/JAVA_LIBRARIES/services_intermediates/classes-full-debug.jar', missing and no known rule to make it

使用LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES编译不报错,但是烧录到设备中,调用时会报错:

text 复制代码
 EdgeGesture not available: com.android.server.policy.EdgeGestureArrowManager

这个错误说明SystemUI找不到类,后面发现修改路径,比如改成EdgeGestureArrowManager:xxx/EdgeGestureArrowManager.jar,编译也不会报错,判断LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES这个方法不行,起码在Android8.1上行不通。

使用LOCAL_STATIC_JAVA_LIBRARIES

  1. LOCAL_STATIC_JAVA_LIBRARIES
    删除LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES这行,改成在LOCAL_STATIC_JAVA_LIBRARIES += 后面添加

    LOCAL_STATIC_JAVA_LIBRARIES := EdgeGestureArrowManager

改法如图:

另外因为jar是要被framework其它代码调用的,所以修改Android.mk时,要把我们的jar写在前面,否则编译会报错:

复制代码
ninja: error: 'out/target/common/obj/JAVA_LIBRARIES/EdgeGestureArrowManager_intermediates/classes.jar', needed by 'out/target/common/obj/JAVA_LIBRARIES/services.core_intermediates/classes-full-debug.jar', missing and no known rule to make it
  1. 创建frameworks/base/libs/EdgeGestureArrowManager/Android.mk
makefile 复制代码
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := EdgeGestureArrowManager
LOCAL_SRC_FILES := EdgeGestureArrowManager.jar
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_MODULE_TAGS := optional
LOCAL_CERTIFICATE := platform
LOCAL_MODULE_SUFFIX := .jar

编译报错:

复制代码
ninja: error: 'out/target/common/obj/JAVA_LIBRARIES/EdgeGestureArrowManager_intermediates/classes.jar', needed by 'out/target/common/obj/JAVA_LIBRARIES/services.core_intermediates/classes-full-debug.jar', missing and no known rule to make it

这里缺少classes.jar我们就把它拷贝出来,

修改frameworks/base/libs/EdgeGestureArrowManager/Android.mk

makefile 复制代码
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := EdgeGestureArrowManager
LOCAL_SRC_FILES := EdgeGestureArrowManager.jar
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_MODULE_TAGS := optional
LOCAL_CERTIFICATE := platform
LOCAL_MODULE_SUFFIX := .jar

# 创建一个规则来生成classes.jar
intermediates.COMMON := $(call local-intermediates-dir,COMMON)

# 定义如何从预构建JAR创建classes.jar
$(intermediates.COMMON)/classes.jar: $(LOCAL_PATH)/$(LOCAL_SRC_FILES) | $(ACP)
	@echo "Copying $< to $@"
	$(copy-file-to-target)

# 设置中间文件
ALL_MODULES.$(LOCAL_MODULE).CLASS.JAR := $(intermediates.COMMON)/classes.jar
ALL_MODULES.$(LOCAL_MODULE).PROTO_CLASSES.JAR := $(intermediates.COMMON)/classes.jar

# 预构建规则
$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/$(LOCAL_SRC_FILES)
	@mkdir -p $(dir $@)
	$(copy-file-to-target)

include $(BUILD_PREBUILT)

这样改完编译会报另外的错误

复制代码
ninja: error: 'out/target/common/obj/JAVA_LIBRARIES/EdgeGestureArrowManager_intermediates/classes.jack', needed by 'out/target/common/obj/JAVA_LIBRARIES/services.core_intermediates/classes.jack', missing and no known rule to make it

这个错误表明AOSP正在使用Jack编译器(Java 8支持),而预构建的JAR没有相应的.jack文件。

AOSP方法编译(详细方案)

先让AOSP编译源代码生成JAR,然后移除源代码,只使用JAR文件

第一步:临时源代码编译

首先创建源代码目录结构:

bash 复制代码
mkdir -p frameworks/base/libs/EdgeGestureArrowManager-tmp/src/com/android/server/policy/

将EdgeGestureArrowManager.java复制到该目录:

bash 复制代码
cp /path/to/your/EdgeGestureArrowManager.java frameworks/base/libs/EdgeGestureArrowManager-tmp/src/com/android/server/policy/

创建临时的Android.mk文件:

临时编译EdgeGestureArrowManager

复制代码
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := EdgeGestureArrowManager
LOCAL_SRC_FILES := \
    src/com/android/server/policy/EdgeGestureArrowManager.java

LOCAL_JAVA_LIBRARIES := \
    core-oj \
    core-libart \
    framework

LOCAL_MODULE_TAGS := optional
LOCAL_CERTIFICATE := platform

# 让AOSP使用Jack编译器
LOCAL_JACK_ENABLED := incremental
LOCAL_DX_FLAGS := --min-sdk-version=21

include $(BUILD_JAVA_LIBRARY)

保存为 frameworks/base/libs/EdgeGestureArrowManager-tmp/Android.mk

第二步:编译获取JAR

bash 复制代码
source build/envsetup.sh
lunch xxx(这里不同项目不一样)
# 编译临时模块获取JAR
mmm frameworks/base/libs/EdgeGestureArrowManager-tmp/
# 从编译输出中找到生成的JAR文件
# 通常在: out/target/common/obj/JAVA_LIBRARIES/EdgeGestureArrowManager_intermediates/classes.jar

第三步:提取jar与jack

上面编译生成的文件:

bash 复制代码
# 复制编译好的JAR文件
cp out/target/common/obj/JAVA_LIBRARIES/EdgeGestureArrowManager_intermediates/javalib.jar  frameworks/base/libs/EdgeGestureArrowManager/EdgeGestureArrowManager.jar

# 注意会生成这个jar,但是要用的不是这个文件./out/target/product/P931/system/framework/EdgeGestureArrowManager.jar

cp out/target/common/obj/JAVA_LIBRARIES/EdgeGestureArrowManager_intermediates/classes.jack frameworks/base/libs/EdgeGestureArrowManager/
bash 复制代码
unzip -l out/target/common/obj/JAVA_LIBRARIES/EdgeGestureArrowManager_intermediates/javalib.jar

正确情况下会输出如下,包含META-INF,classes.dex等文件

text 复制代码
Archive:  out/target/common/obj/JAVA_LIBRARIES/EdgeGestureArrowManager-temp_intermediates/javalib.jar
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2008-01-01 00:00   META-INF/
       64  2008-01-01 00:00   META-INF/MANIFEST.MF
    17660  2008-01-01 00:00   classes.dex
---------                     -------
    17724                     3 files

第四步:清理源代码并更新Android.mk

删除源代码文件:

bash 复制代码
rm -rf frameworks/base/libs/EdgeGestureArrowManager-tmp

# 删除编译生成的临时文件
find out/ -name "EdgeGestureArrowManager*" -exec rm -r {} \;

注意上面是删除了EdgeGestureArrowManager-tmp,之前放jar的EdgeGestureArrowManager目录是不动的,

现在要解决jack报错,需要修改

frameworks/base/libs/EdgeGestureArrowManager/Android.mk

复制代码
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := EdgeGestureArrowManager
LOCAL_SRC_FILES := EdgeGestureArrowManager.jar
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_MODULE_TAGS := optional
LOCAL_CERTIFICATE := platform
LOCAL_MODULE_SUFFIX := .jar

# 创建一个规则来生成classes.jar
intermediates.COMMON := $(call local-intermediates-dir,COMMON)

# 定义如何从预构建JAR创建classes.jar
$(intermediates.COMMON)/classes.jar: $(LOCAL_PATH)/$(LOCAL_SRC_FILES) | $(ACP)
	@echo "Copying $< to $@"
	$(copy-file-to-target)

# 设置中间文件
ALL_MODULES.$(LOCAL_MODULE).CLASS.JAR := $(intermediates.COMMON)/classes.jar
ALL_MODULES.$(LOCAL_MODULE).PROTO_CLASSES.JAR := $(intermediates.COMMON)/classes.jar

# 预构建规则
$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/$(LOCAL_SRC_FILES)
	@mkdir -p $(dir $@)
	$(copy-file-to-target)

# 创建一个规则来生成classes.jack
intermediates.COMMONJACK := $(call local-intermediates-dir,COMMONJACK)

$(intermediates.COMMONJACK)/classes.jack: $(LOCAL_PATH)/classes.jack | $(ACP)
	@echo "Copying $< to $@"
	$(copy-file-to-target)

# 设置中间文件
ALL_MODULES.$(LOCAL_MODULE).CLASS.JACK := $(intermediates.COMMONJACK)/classes.jack
ALL_MODULES.$(LOCAL_MODULE).PROTO_CLASSES.JACK:= $(intermediates.COMMONJACK)/classes.jack

# 预构建规则
$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/$(LOCAL_SRC_FILES)
	@mkdir -p $(dir $@)
	$(copy-file-to-target)

include $(BUILD_PREBUILT)

第五步:更新服务依赖

这个之前有介绍过具体的改法,就是

在 frameworks/base/services/core/Android.mk 中添加:

makefile 复制代码
LOCAL_STATIC_JAVA_LIBRARIES += EdgeGestureArrowManager

第六步:验证集成

复制代码
# 编译服务模块
make libandroid_servers -j16

这样就完成了整个流程:先用AOSP编译源代码得到JAR文件,然后移除源代码,只使用JAR进行后续的集成。这样既保持了闭源的要求,又解决了编译的问题。

这样就能获得正确的.jack文件,然后可以使用BUILD_JAVA_LIBRARY来集成它。
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/aa84373964df4e5093be668bf15f8d5b.png)
```bash
# 检查services模块是否包含EdgeGestureArrowManager类
unzip -l out/target/common/obj/JAVA_LIBRARIES/services_intermediates/classes.jar | grep EdgeGesture

在out目录下会找到这些编译的中间文件

这样再编译整个系统,烧录到设备中,测试代码调用正常了。

proguard混淆加密

低版本的Android可能无法使用proguard混淆,这里只是为了适配高版本Android及为了低版本的失败做验证。

首先存放java的这个EdgeGestureArrowManager-tmp需要还原回去,要在这个目录下操作,

proguard,可以自行到github上下载

复制代码
https://github.com/Guardsquare/proguard/releases

解压后,把里面的proguard.jar把放到EdgeGestureArrowManager-tmp/libs下

重新编译jar

bash 复制代码
source build/envsetup.sh
lunch xxx(这里不同项目不一样)
# 编译临时模块获取JAR
mmm frameworks/base/libs/EdgeGestureArrowManager-tmp/

编完后,检查下混淆是否生效,

bash 复制代码
ls -la out/target/common/obj/JAVA_LIBRARIES/EdgeGestureArrowManager-tmp_intermediates/ | grep proguard

上面指令输出为空,最后发现Android8用jack编译情况Proguard未生效。

据说Jack编译器有自己的混淆机制,LOCAL_PROGUARD_ENABLED 可能被忽略。

尝试显式启用Jack混淆

在Android.mk中添加:

makefile 复制代码
# 显式启用Jack混淆
LOCAL_JACK_FLAGS += --obfuscate

最后编译出来的,发现没有被混淆,可能Jack不支持混淆,使用另外的思路,关闭Jack,开启Dx并使用Proguard混淆。

修改Android.mk

makefile 复制代码
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := EdgeGestureArrowManager
LOCAL_SRC_FILES := \
    src/com/android/server/policy/EdgeGestureArrowManager.java

LOCAL_JAVA_LIBRARIES := \
    core-oj \
    core-libart \
    framework

LOCAL_MODULE_TAGS := optional
LOCAL_CERTIFICATE := platform

# 显式禁用 Jack(即使全局启用也不影响)
LOCAL_JACK_ENABLED := disabled

# 启用Proguard混淆
LOCAL_PROGUARD_ENABLED := obfuscation
LOCAL_PROGUARD_FLAG_FILES := proguard.flags

include $(BUILD_JAVA_LIBRARY)

安装需要的desugar,dx

bash 复制代码
m desugar
m dx

再编译EdgeGestureArrowManager,如下图编译成功,并开启Proguard了:

解压jar,得到classes.dex,再搜索其中的类名关键字EdgeGesture(这个类名由java代码定的,请自行根据自己的类变更):

bash 复制代码
unzip -p unzip -p out/target/common/obj/JAVA_LIBRARIES/EdgeGestureArrowManager_intermediates/javalib.jar classes.dex > /tmp/classes.dex
strings /tmp/classes.dex | grep -i "EdgeGesture"

如果没有输出,则说明混淆成功了。

把编译成功的jar拷贝出来,并删除编译的中间文件,及java源码

bash 复制代码
cp out/target/common/obj/JAVA_LIBRARIES/EdgeGestureArrowManager-tmp_intermediates/javalib.jar frameworks/base/libs/EdgeGestureArrowManager/EdgeGestureArrowManager.jar

find out/ -name "EdgeGestureArrowManager*" -exec rm -r {} \;

rm -r frameworks/base/libs/EdgeGestureArrowManager-tmp

修改frameworks/base/libs/EdgeGestureArrowManager/Android.mk

把jack的拷贝去掉

makefile 复制代码

Android相关专栏

Android Framework专栏链接
Android专栏

作者:帅得不敢出门

相关推荐
墨^O^2 小时前
并发控制策略与分布式数据重排:锁机制、Redis 分片与 Spark Shuffle 简析
java·开发语言·c++·学习·spark
丶小鱼丶2 小时前
数据结构和算法之【阻塞队列】上篇
java·数据结构
火山上的企鹅2 小时前
QGC 二次开发实战:Android 单机离线授权怎么落地
android·qt·qgroundconrol·离线授权
zb200641202 小时前
MySQL——表操作及查询
java
人道领域2 小时前
LeetCode【刷题日记】:滑动窗口算法详解:从暴力法到最优解
java·算法·leetcode
黄林晴2 小时前
Swift 杀进 Android,Google 和 Apple 都要失眠了?
android·前端·swift
迷藏4942 小时前
# 发散创新:用Locust实现高并发场景下的精准压力测试实战在现代微服务架构中,**系统稳定性与性能瓶颈的识别能力直接决定了产品上线后
java·python·微服务·架构·压力测试
黄林晴2 小时前
改完代码1秒生效,Compose热重载来了!
android