/ Embedded

How to use Android Studio to build system application?

Before, we have Eclipse IDE to improve develop System Application for Android project, but now we have Android Studio. How use Android Studio to build system application?

I'm working on one AOSP (Android Open Source Project) project. In this project, there are some application need to be customize. E.g. Settings, Launcher. While developing the Settings application, it will use some hidden API which is not public in Android SDK. E.g from EthernetManager. Therefore, it need the framework.jar which include hidden API for System Application. The following is the way to compile the application:

  • Find the uncompressed framework.jar under /android/out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar. Please be careful, not the /android/out/target/product/your_target/system/framework/framework.jar. The first one is unstripped java library. The second one is which we are using for official Android SDK library.
  • Copy it to the project path /project_path/system_libraries, and rename it framework.jar.
  • Add 'provided' to dependencies, this step is like Eclipse to set the extended library.
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.4.0'
    provided fileTree(dir: 'system_libraries', include: ['*.jar'])
}

Then the developing application can recognized 'EthernetManager' now.

But still met an issue is this API seem not work for now. While using framework.jar to replace Android SDK framework.jar , we met one issue. e.g. While using WifiManager, Android SDK has some public API for WifiManager, and from framework.jar there are some hidden API for WifiManager. If you just compile it, it's still have the issue. In the old way, Eclipse IDE can set the dependency index to know which one is the first import. But in Android Studio, it will always put Android SDK framework to the first import. Therefore, we need to find a way to put the framework before than Android SDK.

  • There is one file called app.iml. It has <orderEntry> for different library. We put the <orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" /> as the last one. Then Android Studio can use our own framework.jar.
  • The file app.iml mentioned above will changed by Android Studio automaticlly, therefore we create a new task to change it while Gradle sync.
task pushDownJdkDependency {
    def imlFile = file("app.iml")
    println 'Change app.iml order'
    try {
        def parsedXml = (new XmlParser()).parse(imlFile)
        def jdkNode = parsedXml.component[1].orderEntry.find { it.'@type' == 'jdk' }
        parsedXml.component[1].remove(jdkNode)
        new Node(parsedXml.component[1], 'orderEntry', ['type': 'jdk', 'jdkName': "Android API 23 Platform", 'jdkType': 'Android SDK'])
        def writer = new StringWriter()
        new XmlNodePrinter(new PrintWriter(writer)).print(parsedXml)
        imlFile.text = writer.toString()
        } catch (FileNotFoundException e) {
            // nop, iml not found
        }
    }
}
  • After that the preBuild will be ok, but while generating the package, it still will got compile error. We add one hook to Android Gradle plugin, -Xbooclasspath/p: is add classpath before bootstarp classpath, see link
gradle.projectsEvaluated {
    preBuild.dependsOn(brandCopy)
    tasks.withType(JavaCompile) {
        options.compilerArgs.add('-Xbootclasspath/p:app/system_libraries/framework.jar')
    }
}
  • These two snips should put before android closure to make sure it works for building process.

After these steps, now we can use Android Studio to build the System Application. Have fun with your coding :)