如何在android gradle插件环境中支持osgi?

时间:2015-07-19 01:19:05

标签: android groovy gradle osgi

我想将apk用作osgi包,然后将其加载到主机应用程序中。

现在,它运作正常。但是在将osgi包推送到手机之前我必须手动执行这些操作:

  1. 使用WinRAR打开osgi bundle apk文件。
  2. 将构建的类(在extension-a \ build \ intermediates \ classes \ debug \ com中)拖到bundle文件的根目录。
  3. 将修改后的MANIFEST.MF(包括OSGI配置信息)拖到捆绑文件“META-INFO / MANIFEST.MF”。
  4. 最后签署了捆绑包。
  5. 我想知道如何编写一些gradle脚本来自动执行这些操作?

    我使用gradle 2.2.1和' com.android.tools.build:gradle:1.2.3'。

    PS: 我知道有一个gradle插件" osgi"可以为osgi bunlde生成MANIFEST.MF,但它只适用于" java" gradle插件。 我不能用" android" gradle插件。

    我试过这种方式:

    android.applicationVariants.all { variant ->
        variant.outputs[0].packageApplication.doLast {
            String zipFileName = variant.outputs[0].outputFile.name
            String inputFile = 'MANIFEST.MF'  
    
            def zipIn = variant.outputs[0].outputFile
            def zip = new ZipFile(zipIn.getAbsolutePath())
            def zipTemp = new File(zipFileName + "_temp") 
            zipTemp.deleteOnExit()
            def zos = new ZipOutputStream(new FileOutputStream(zipTemp))
            def toModify = 'META-INFO/MANIFEST.MF'
    
            for(e in zip.entries()) {
                if(!e.name.equalsIgnoreCase(toModify)) {
                    zos.putNextEntry(e)
                    zos << zip.getInputStream(e).bytes
                } else {
                    zos.putNextEntry(new ZipEntry(toModify))
                    zos << new File(inputFile).bytes
                }
                zos.closeEntry()
            }
    
            zos.close()
            zipIn.delete()
            zipTemp.renameTo(zipIn)
        }
    }
    

    但没有成功:

    1. 如果使用&#34; gradle clean build&#34;,则报告&#34; out-file.apk&#34;没找到。
    2. 如果out-file.apk存在,则报告异常:

      java.util.zip.ZipException:无效的条目压缩大小(预期为400但是有401个字节) at java.util.zip.ZipOutputStream.closeEntry(Unknown Source)

    3. 任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

我找到了解决问题的方法。

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.2.3'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

apply plugin: 'com.android.application'

import java.util.zip.*

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.2"

    defaultConfig {
        minSdkVersion 19
        targetSdkVersion 21
        sourceCompatibility = '1.7'
        targetCompatibility = '1.7'
        versionCode 1
        versionName "1.0"
    }

    signingConfigs {
        release {
            storeFile file("debug.keystore") // should move debug.keystore to build.gradle directory
            keyAlias "androiddebugkey"
            storePassword "android"
            keyPassword "android"
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release            
        }

        android.applicationVariants.all { variant ->
            variant.outputs[0].packageApplication.doLast {
                println "Add osgi files after packageApplication ..."

                def manifestFile = 'MANIFEST.MF'  
                def toModify = 'META-INF/MANIFEST.MF'
                def classesPath =  "build/intermediates/classes/"+variant.buildType.name+"/com"
                def zipFile = variant.outputs[0].outputFile.getAbsolutePath()

                //if (variant.buildType.name.equals("debug"))
                // After config release signingConfig, should change apk name, so remove this if statement
                zipFile = zipFile.replace(".apk", "-unaligned.apk")

                //release should change 3 positions: (If without release signingConfig)
                //  1. no need replace name with -unaligned.apk; 
                //  2. copy intermediates/classes/release/com; 
                //  3. should add META-INF/MANIFEST.MF, not replace.
                updateZipEntry(zipFile, toModify, manifestFile, classesPath)

                signApkFile(zipFile)
                //println project.buildDir
                //println System.getenv('JAVA_HOME')
            }
        }
    }
}

dependencies {
    provided fileTree(dir: 'src/main/libs', include: ['*.jar'])
    provided 'org.apache.felix:org.apache.felix.framework:5.0.0'
}

void updateZipEntry(String zipFile, String zipEntry, String newFile, String classesPath){
    def zin = new ZipFile(zipFile)
    def tmp = File.createTempFile("temp_${System.nanoTime()}", '.zip')
    tmp.withOutputStream { os ->
        def hasReplaced = false
        def zos = new ZipOutputStream(os)
        zin.entries().each { entry ->
            def isReplaced = entry.name == zipEntry
            entry.setCompressedSize(-1);
            zos.putNextEntry(isReplaced ? new ZipEntry(zipEntry) : entry)
            zos << (isReplaced ? new File(newFile).bytes : zin.getInputStream(entry).bytes )
            zos.closeEntry()
            if (isReplaced) hasReplaced = true
        }
        if (!hasReplaced) { // Add META-INF/MANIFEST.MF for release build.
            zos.putNextEntry(new ZipEntry(zipEntry))
            zos << new File(newFile).bytes
            zos.closeEntry()
        }
        addDirToArchive(zos, new File(classesPath), "com")
        zos.close()
    }
    zin.close()
    assert new File(zipFile).delete()
    tmp.renameTo(zipFile)
}

void addDirToArchive(ZipOutputStream zos, File srcDir, String dstDir) {
    //System.out.println("Adding directory: " + srcDir.getName() + " -> " + dstDir);

    File[] files = srcDir.listFiles();
    for (int i = 0; i < files.length; i++) {
        // if the file is directory, use recursion
        if (files[i].isDirectory()) {
            addDirToArchive(zos, files[i], dstDir + "/" + files[i].getName());
            continue;
        }
        try {
            //System.out.println("Adding file: " + files[i].getName());

            // create byte buffer
            byte[] buffer = new byte[1024];
            FileInputStream fis = new FileInputStream(files[i]);
            zos.putNextEntry(new ZipEntry(dstDir + "/" + files[i].getName()));
            int length;
            while ((length = fis.read(buffer)) > 0) {
                zos.write(buffer, 0, length);
            }
            zos.closeEntry();

            // close the InputStream
            fis.close();
        } catch (IOException ioe) {
            System.out.println("IOException :" + ioe);
        }
    }
}

void signApkFile(String zipFile) {
    def signApkCmdLine = "java -Xmx512m -jar signapk.jar -w testkey.x509.pem testkey.pk8 "+zipFile+" "+zipFile
    def sout = new StringBuffer(), serr = new StringBuffer()
    def proc = signApkCmdLine.execute()
    proc.consumeProcessOutput(sout, serr)
    proc.waitForOrKill(1000)
    println "sign apk : out> $sout err> $serr"
}