AndroidStudio 开发系统app(解决了可能遇到的所有问题)

文章目录

    • 前言
    • 安装带有系统权限的APP
      • 1. 准备如下文件
      • 2. 生成keystore文件
      • 3. 配置gradle
    • 使用非公开的资源或者API(导入framework.jar)
      • 1. 拷贝源码全编后的 framework.jar
      • 2. 放入APP libs目录`ScanSettings/app/libs/framework.jar`
      • 3. 模块APP的build.gradle 引入framework.jar
      • 4. 运行,如果正常就恭喜你了,不用看下面的步骤
      • 5. 问题:依然无法找到对应系统内部资源
      • 6. 问题:编译出现 Build on Android fails with ArrayIndexOutOfBoundsException: 65535

前言

手机系统App开发人员编写代码时使用AndroidStudio,编译时通过 Android.mk 编译,在 Android9.0 上模块编译速度更是不敢恭维,用时单位是以分钟计算的。为了解决编译速度问题,强烈推荐使用 AndroidStudio编译。但是通过gradle编译又会出现各种问题,例如安装android:sharedUserId="android.uid.system"权限的APK,没关系,下面就带你一一解决这些问题。

安装带有系统权限的APP

我们的App需要系统权限时,需要在 AndroidManifest.xml 配置

android:sharedUserId="android.uid.system"

这样配置后直接是无法运行的,因为签名必须是平台签名,我们需要对其进行系统签名然后方可安装。

1. 准备如下文件

  1. keytool-importkeypair Github下载地址
  2. Android证书文件 platform.x509.pem、platform.pk8 (位于build/target/product/security/)下

2. 生成keystore文件

将 keytool-importkeypair、platform.pk8和platform.x509.pem文件放在同一个目录下,执行如下命令,生成platform.keystore文件:

./keytool-importkeypair -k platform.keystore -p 123456 -pk8 platform.pk8 -cert platform.x509.pem -alias platform

下面是本人自己执行的及输出结果,底部有Warning 没有关系。

nan@breeze:~/Tools/sign_app/keytool-importkeypair-master$ ./keytool-importkeypair -k platform.keystore -p 123456 -pk8 platform.pk8 -cert platform.x509.pem -alias platform
Importing "platform" with SHA1 Fingerprint=5A:73:D9:4D:F2:CF:1B:6C:41:71:98:BB:C2:16:E4:4F:4D:F6:70:D3
Importing keystore /tmp/keytool-importkeypair.Wqxz/p12 to platform.keystore...
Entry for alias platform successfully imported.
Import command completed:  1 entries successfully imported, 0 entries failed or cancelled

Warning:
The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore platform.keystore -destkeystore platform.keystore -deststoretype pkcs12".
  • -k: 表示生成的签名文件名称,此处为platform.keystore,也可以为platform.jks,名称任意起。
  • -p: 表示新生成的keystore的密码是什么,此处为123456
  • -pk8: 表示要导入的pk8文件的名称,可以包括路径,pk8文件用来保存private key的,是个私钥文件。
  • -cert: 表示要导入的证书文件,pem这种文件就是一个x.509的数字证书,里面有用户的公钥等信息,是用来解密的,这种文 件格式里面不仅可以存储数字证书,还能存各种key。(有兴趣的可以点击此了解一下)
  • -alias: 表示给生成的platform.keystore取一个别名,这个名字只有我们在签名的时候才用的到,这里我们的别名起为platform。这个名字,可以随便取,但是你自己一定要记住。

另外keytool -list -v -keystore xxx.jks可以查看key的详细信息

nan@breeze:~/Tools/sign_app/keytool-importkeypair-master$ keytool -list -v -keystore platform.keystore 
Enter keystore password:  
Keystore type: JKS
Keystore provider: SUN

Your keystore contains 1 entry

Alias name: platform
Creation date: Dec 7, 2019
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: [email protected], CN=VPN, OU=Software Engineering, O=XXX Networks, L=City of Industry, ST=California, C=US
Issuer: [email protected], CN=VPN, OU=Software Engineering, O=XXX Networks, L=City of Industry, ST=California, C=US
Serial number: eccdd3f4278092c5
Valid from: Wed Oct 30 10:25:50 CST 2019 until: Sun Mar 17 10:25:50 CST 2047
Certificate fingerprints:
	 MD5:  E5:74:F5:01:F4:FA:E3:EE:2D:B4:48:6D:FC:A0:B1:6F
	 SHA1: 5A:73:D9:4D:F2:CF:1B:6C:41:71:98:BB:C2:16:E4:4F:4D:F6:70:D3
	 SHA256: CF:AA:1F:D4:71:6E:74:E2:47:5F:C4:84:B0:86:B9:74:BE:98:46:58:3D:AE:17:20:B4:34:DC:F3:F1:37:D0:9C
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3
...

3. 配置gradle

模块的build.gradle中配置如下

defaultConfig {
    applicationId "com.base.module.callapp"
    minSdkVersion 28
    targetSdkVersion 29
    versionCode 1
    versionName "1.0"

}
// wangyannan add begin
signingConfigs {
    release {
        // CallApp/signapk/platform.keystore 自己创建路径,放入即可,其他路径也可以
        storeFile file("../signapk/platform.jks")
        storePassword '123456'
        keyAlias 'platform'
        keyPassword '123456'
    }

    debug {
        storeFile file("../signapk/platform.jks")
        storePassword '123456'
        keyAlias 'platform'
        keyPassword '123456'
    }
}
// wangyannan add end

大功告成,已经可以运行了,可能会提示与系统中安装的APK签名不一致,替换即可。如果无法运行,rebuild一下或者重启studio 即可。

但是这只是可以运行带有android.uid.system权限的APP。假如我们需要使用com.android.internal.R.drawable.ic_text_dot 类似这种系统内部资源或者API时,我们是没有提示的,且会编译错误,但是作为系统APP本应是可以使用的,怎么解决?下面这种方法获取

Resources.getSystem().getIdentifier("ic_text_dot", "drawable", "android")

这种方法是针对第三方APP的,未免对于我们具有系统权限的APP有点掉价,一个字low,两个字庸俗。

看我怎么教你就通过com.android.internal.R.drawable.ic_text_dot这种使用,且具有提示。

使用非公开的资源或者API(导入framework.jar)

1. 拷贝源码全编后的 framework.jar

jar包为
out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar,class.jar 重命名为framework.jar

2. 放入APP libs目录ScanSettings/app/libs/framework.jar

3. 模块APP的build.gradle 引入framework.jar

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'com.google.android.material:material:1.2.0-alpha02'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    // wangyannan add begin    
    compileOnly files('libs/framework.jar')
    // wangyannan end end
}

4. 运行,如果正常就恭喜你了,不用看下面的步骤

这时运行可能遇到两个问题,别怕,我会告诉你解决办法。

5. 问题:依然无法找到对应系统内部资源

模块APP的build.gradle 加入如下code

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'com.google.android.material:material:1.2.0-alpha02'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    // wangyannan add begin    
    compileOnly files('libs/framework.jar')
    // wangyannan end end
}
// wangyannan add begin 
preBuild {
    doLast {
        def imlFile = file(project.name + ".iml")
        println 'Change ' + project.name + '.iml order'
        try {
            def parsedXml = (new XmlParser()).parse(imlFile)
            def jdkNode = parsedXml.component[1].orderEntry.find { it.'@type' == 'jdk' }
            parsedXml.component[1].remove(jdkNode)
            def sdkString = "Android API " + android.compileSdkVersion.substring("android-".length()) + " Platform"
            new Node(parsedXml.component[1], 'orderEntry', ['type': 'jdk', 'jdkName': sdkString, 'jdkType': 'Android SDK'])
            groovy.xml.XmlUtil.serialize(parsedXml, new FileOutputStream(imlFile))
        } catch (FileNotFoundException e) {
            // nop, iml not found
        }
    }
}
// wangyannan add end

工程build.gradle加入

allprojects {
    repositories {
        google()
        jcenter()
        
    }
    // wangyannan add begin, 最好全路径,相对路径不一定能过
    gradle.projectsEvaluated {
        tasks.withType(JavaCompile) {
            options.compilerArgs.add('-Xbootclasspath/p:/home/nan/Dog/project/wp850/android/packages/apps/ScanSettings/app/libs/framework.jar')
        }
    }
    // wangyannan add end
}

加入这些是为了解决Androidstudio默认使用自带sdk,而不使用framework.jar的问题。

6. 问题:编译出现 Build on Android fails with ArrayIndexOutOfBoundsException: 65535

编译失败是由于Android存在只能有 64k 个方法的限制,这是由于Dalvik执行规则限制。我们可以通过开启 Multidex 即可绕过 64k 限制,如果你的 minSdkVersion 设置为 21 或更高值,默认情况下就启用了多 dex 文件,但如果小于,可以参考官方文档开启。具体可见点此处。

此时如果还是报错,请确保 AndroidStudio 兼容 java8,具体配置如下

android {
    ...
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

好了,这个时候世界就美好了。

如果这篇文章对你有用,请留个赞:),如果有疑问也可以留言哦!,

参考:

  • AndroidStudio 配置系统签名
  • 在android studio中加入framework.jar的方法

你可能感兴趣的:(Android开发,开发系统app,AndroidStudio,使用非公开资源)