Android Studio + Gradle编译整机APK

转载注明出处:https://blog.csdn.net/skysukai

进行Android Rom开发的时候通常会有好多系统预置apk需要进行开发维护。一般来讲,这些apk开发需要依赖系统码源进行编译,而编译一个apk又需要把它push到手机里,费时费力。有没有办法像普通APP开发一样,做到即时运行呢?这就是本篇文章要解决的问题。

1、需要解决的问题

要使用Gradle来编译整机apk需要解决的问题有两个:签名、framework的动态链接。

2、签名

Android平台的签名分为四种,分别是 media、platform、shared、testkey。同的签名文件对应不同的权限,Android默认的签名文件为testkey。

2.1确认签名类型

通过mmmma来编译整机apk时,需要确定编译的apk的签名类型,在Android.mk文件中来确定:

LOCAL_CERTIFICATE := platform

LOCAL_CERTIFICATE规定了将编译的apk的签名类型:platform。

2.2生成签名文件

mk文件规定了需要生成platform的签名文件,网上有许多生成platform签名文件的生成方法,笔者最开始生成时也是按照这些方法来做的,不过,这些方法都是错的,费了不少时间(参考)。直接给出签名命令:

1、生成platform.pem
openssl pkcs8 -in platform.pk8 -inform DER -outform PEM -out shared.priv.pem
2、生成platform.pk12
openssl pkcs12 -export -in platform.x509.pem -inkey shared.priv.pem -out shared.pk12 -name 你的签名名字(如:android)
3、生成keystore文件
keytool -importkeystore -deststorepass 你的签名文件密码(如:android) -destkeypass 你的签名文件密码(如:android) -destkeystore platform.keystore -srckeystore shared.pk12 -srcstoretype PKCS12 -srcstorepass 你的签名文件密码(如:android) -alias 你的签名名字(如:android)

网上给出的签名过程通常错在第一步:

openssl pkcs8 -in platform.pk8 -inform DER -outform PEM -out shared.priv.pem -nocrypt

-nocrypt的意思是不需要密码,但通常每个公司都有自己的密码,去掉这个参数即可。
按以上步骤即可得到platform.keystore这个签名文件了。

3、动态链接到framework

整机apk通常都要依赖framework,需要在build.gradle中动态链接到framework。需要先将framework.jar放到工程里。需要的build.gradle文件读者如果没有可以上网找一个或由IDE自动生成。链接到framework其实一句话即可解决问题:

gradle.projectsEvaluated {
        tasks.withType(JavaCompile) {
            options.compilerArgs << '-Xbootclasspath/p:' + rootDir + '你存放framework.jar的路径(如:/config/framework.jar)'    
        }
    }

这样代码运行的时候就会动态链接到framework,为了增加可读性,可以在设置依赖的地方增加以下一句:

compileOnly files(你存放framework.jar的路径(如:rootProject.getRootDir().getAbsolutePath()+ '/config/framework.jar'))

4、mk文件的修改

如果采用gradle来编译整机代码,也需保证编译整机rom的时候能正常编译,在mk文件里需要完成的工作就是触发gradle编译。 先给出一个编译脚本build.sh:

……
GRADLE_SYNC_ENV=0
GRADLE_TASK_CLEAN=0
GRADLE_TASK_ALL=0
GRADLE_TASK_RELEASE=0
GRADLE_TASK_BETA=0
GRADLE_TASK_DEBUG=0
GRADLE_MAKEFILE=0
GRADLE_PATH=.
GRADLE_INSTALL_APK=0

# Add executable permissions
chmod +x ${GRADLE_PATH}/gradlew

# Do gradle build
if [[ ${GRADLE_TASK_CLEAN} == 1 ]]
then
    ${GRADLE_PATH}/gradlew -p ${GRADLE_PATH} clean
elif [[ ${GRADLE_TASK_ALL} == 1 ]]
then
    ${GRADLE_PATH}/gradlew -p ${GRADLE_PATH} clean assemble
elif [[ ${GRADLE_TASK_RELEASE} == 1 ]] && [[ ${GRADLE_INSTALL_APK} == 1 ]]
then
    ${GRADLE_PATH}/gradlew -p ${GRADLE_PATH} clean installRelease
elif [[ ${GRADLE_TASK_RELEASE} == 1 ]]
then
    ${GRADLE_PATH}/gradlew -p ${GRADLE_PATH} clean assembleRelease
elif [[ ${GRADLE_TASK_BETA} == 1 ]] && [[ ${GRADLE_INSTALL_APK} == 1 ]]
then
    ${GRADLE_PATH}/gradlew -p ${GRADLE_PATH} clean installBeta
elif [[ ${GRADLE_TASK_BETA} == 1 ]]
then
    ${GRADLE_PATH}/gradlew -p ${GRADLE_PATH} clean assembleBeta
elif [[ ${GRADLE_TASK_DEBUG} == 1 ]] && [[ ${GRADLE_INSTALL_APK} == 1 ]]
then
    ${GRADLE_PATH}/gradlew -p ${GRADLE_PATH} installDebug
elif [[ ${GRADLE_TASK_DEBUG} == 1 ]]
then
    ${GRADLE_PATH}/gradlew -p ${GRADLE_PATH} assembleDebug

# Makefile compile do not need version name flag
if [[ ${GRADLE_MAKEFILE} == 1 ]]
then
    # This scene will do clean, so do not need to deal with multiple apk scene.
    for APK_PATH in $(find ${GRADLE_PATH}/app/build/outputs/apk -name "*.apk")
    do
        if [[ ${APK_PATH} != $(dirname ${APK_PATH})/你的apk.apk ]]
        then
            mv ${APK_PATH} $(dirname ${APK_PATH})/你的apk.apk.apk
            checkCMDStatus $?
        fi
    done
fi
……
# Launch built apk
……

需要注意的是,minSdkVersiontargetSdkVersion也需要和gradle版本配置好,编译如果有错按提示修改即可。
接下来修改mk文件。mk文件中只需要触发gralde编译即可:

LOCAL_PATH := $(call my-dir)

YOURAPK_GRADLE_PATH := $(LOCAL_PATH)
YOURAPK_CHECK_CMD := $(YOURAPK_GRADLE_PATH)/build.sh -e -m $(YOURAPK_GRADLE_PATH)
YOURAPK_CLEAN_CMD := $(YOURAPK_GRADLE_PATH)/build.sh -c -m $(YOURAPK_GRADLE_PATH)
ifeq ($(TARGET_BUILD_VARIANT), user)
YOURAPK_ASSEMBLE_CMD := $(YOURAPK_GRADLE_PATH)/build.sh -r -m $(YOURAPK_GRADLE_PATH)
YOURAPK_APK_PATH := app/build/outputs/apk/release
else
YOURAPK_ASSEMBLE_CMD := $(YOURAPK_GRADLE_PATH)/build.sh -b -m $(YOURAPK_GRADLE_PATH)
YOURAPK_APK_PATH := app/build/outputs/apk/beta
endif

# If there is no YOURAPK_APK_PATH directory, the APK Build will not be trigger.
ifeq (, $(wildcard $(YOURAPK_APK_PATH)))
$(shell mkdir -p $(YOURAPK_APK_PATH))
endif

# Add executable permissions
$(shell chmod +x $(YOURAPK_GRADLE_PATH)/build.sh)

.PHONY: APK Build
filemanagerBuild:
	@echo "Run gradlew assemble command"
	@rm -rf $(YOURAPK_GRADLE_PATH)/app/.externalNativeBuild
	@$(YOURAPK_CHECK_CMD)
	@$(YOURAPK_ASSEMBLE_CMD)

$(YOURAPK_GRADLE_PATH)/$(YOURAPK_APK_PATH)/%.apk: APK Build
	@echo "FileManager APK file is ready for $@"

.PHONY: clean
clean:
	@echo "Run APK gradlew clean command"
	@rm -rf $(YOURAPK_GRADLE_PATH)/app/.externalNativeBuild
	@$(YOURAPK_CHECK_CMD)
	@$(YOURAPK_CLEAN_CMD)


include $(CLEAR_VARS)
LOCAL_MODULE := YOUR_MODULE
LOCAL_OVERRIDES_PACKAGES := YOUR_ OVERRIDES_PACKAGES
LOCAL_SRC_FILES := $(YOURAPK_APK_PATH)/你的apk.apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_PRIVILEGED_MODULE := false
LOCAL_MODULE_TAGS := optional

LOCAL_CERTIFICATE := platform
include $(BUILD_PREBUILT)

通过以上步骤即完成了在mk文件中触发gradle编译apk,而不影响整机rom的编译。

5、混淆

完成了以上步骤后,就实现了用Android Studio + Gradle来编译整机apk。还差最后一步就是apk的混淆。发布的apk进行混淆后的好处显而易见,除了提高安全性以外,最大的好处就是缩小apk的体积。给出一个通用的混淆模板,如果有不需要混淆的类在上边加上就好。

# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}

# Code compression level
-optimizationpasses 5
# Do not use case mixing
-dontusemixedcaseclassnames
# Do not ignore non-public library classes
-dontskipnonpubliclibraryclasses
# Do not ignore members of the library class visible to the package
-dontskipnonpubliclibraryclassmembers
# Specifies not to optimize the input class files.
# By default, optimization is enabled; all methods are optimized at a bytecode level.
# If optimization is disabled, other optimized option like 'optimizationpasses'/'optimizations' will not work.
#-dontoptimize
# No pre-verification,speed up obfuscating
-dontpreverify
# Block warning
-ignorewarnings
# Specify the algorithm used for obfuscating
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
# Keep Annotation
-keepattributes *Annotation*
# Keep generics, for JSON
-keepattributes Signature
# Retain the code line number when an exception is thrown
-keepattributes SourceFile,LineNumberTable
# Allow access to and modify members of classes and classes with modifiers
-allowaccessmodification
# Only for -repackageclasses
-repackageclasses ''
# Keep obfuscating compilation log
-verbose
# Optional, do not shrink useless code
#-dontshrink
# Optional, do not obfuscate code
#-dontobfuscate

# Default keep activity/application/service/broadcastReceiver/contentprovider...
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.support.multidex.MultiDexApplication
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep class android.support.** {*;}

# Keep ILicensingService/ILicensingService for google service
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService

# Keep basic jars from Android
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**

# Keep native method
-keepclasseswithmembernames class * {
    native <methods>;
}

# Keep 'android:onclick="onClick"' in XML
-keepclassmembers class * extends android.app.Activity{
    public void *(android.view.View);
}

# Keep values()/valueOf() in enum
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

# Keep setXxx()/getXxx() in View
-keep public class * extends android.view.View{
    *** get*();
    void set*(***);
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

# Keep classes extends from Parcelable
-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}

# Keep classes extends from Serizalizable
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}

#-keep class **.R$* {
# *;
#}
# Keep resource static
-keepclassmembers class **.R$* {
    public static <fields>;
}

# Keep onXXEvent/**On*Listener
-keepclassmembers class * {
    void *(**On*Event);
    void *(**On*Listener);
}

# Keep customize views
-keep public class * extends android.view.View{
    *** get*();
    void set*(***);
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}


# Keep entity model
-dontwarn com.suchengkeji.android.confusiondemo.md.**
# Processing with reflections
-keep class com.suchengkeji.android.confusiondemo.md.** { *; }

# Keep testing related code
-dontnote junit.framework.**
-dontnote junit.runner.**
-dontwarn android.test.**
-dontwarn android.support.test.**
-dontwarn org.junit.**

#
# ----------------------------- other 3rd jars -----------------------------
#

6、收尾工作

在进行了上面所有步骤后,需要对apk做全量遍历,防止由混淆编译及Gradle编译引入的功能回退,保证apk质量。

相关参考:https://www.jianshu.com/p/63d699cffa1a
相关参考:https://www.jianshu.com/p/9df3c3b6067a
相关参考:https://www.jianshu.com/p/e9d3c57ab92f?utm_campaign=haruki&utm_content=note&utm_medium=reader_share&utm_source=qq
相关参考:https://blog.csdn.net/zhangfeng5909/article/details/80856095
相关参考:https://blog.csdn.net/xu_coding/article/details/80819494
相关参考:https://blog.csdn.net/chzphoenix/article/details/75470846
相关参考:https://blog.csdn.net/sunquan1992/article/details/64918727
相关参考:https://www.jianshu.com/p/b471db6a01af
相关参考:https://www.guardsquare.com/en/products/proguard/manual/usage
相关参考:https://blog.csdn.net/cauchyweierstrass/article/details/53261581
相关参考:https://blog.csdn.net/ccpat/article/details/52059344
相关参考:https://blog.csdn.net/geekqian/article/details/78961835

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值