2015-07-19 79 views
2

我想使用apk作爲一個osgi包,然後將其加載到主機應用程序中。如何在android gradle插件環境中支持osgi?

現在,它工作正常。但我必須手動做這些事情之前推OSgi捆綁電話:

  1. 打開osgi包與WinRAR的apk文件。
  2. 將構建的類(在extension-a \ build \ intermediates \ classes \ debug \ com中)拖到包文件的根目錄中。
  3. 將修改後的MANIFEST.MF(包括OSGI配置信息)拖到包文件的META-INFO/MANIFEST.MF中。
  4. 最後簽名包apk。

我想知道如何編寫一些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. 如果使用 「gradle這個乾淨的構建」,它報告 「出file.apk」 找不到。
  2. 如果出file.apk存在,其報告的異常:

    java.util.zip.ZipException:無效輸入壓縮後的大小(預期400,但得到401個字節)在java.util.zip.ZipOutputStream中 .closeEntry(未知來源)

任何幫助,將不勝感激!

回答

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" 
}