среда, 14 сентября 2011 г.

Автоматическая сборка проекта Ant-ом и выкладывание его на ftp.

Постановка задачи: Есть начальные настройки программы для конкретного клиента: IP1, IP2, port и т.д. У меня есть список клиентов, и настройки, которые соответствуют каждому клиенту. Для того чтобы не вводить их после скачивания и установки apk файла, нужно вшить эти настройки в каждую сборку. То есть для каждого клиента должна быть своя, настроенная на него, сборка приложения.
Версия Android-а: 1.6
      1) нужно убедиться что у нас стоит последняя версия Ant-а, если это не так качаем и устанавливаем.( http://ant.apache.org/manualdownload.cgi ) и последняя версия Android SDK
      2) создаем build.xml в папке с проектом, со следующим содержимым:

<?xml version="1.0" encoding="UTF-8"?>
<project name="1616" >
  <property name="sdk.dir" location="C:\Progra~1\Android\android-sdk" />
  <property file="local.properties" />
  <property name="source.dir" value="src" />
  <property name="clojure.source.dir" value="src/clojure" />
  <property name="clojure.source.absolute.dir" location="${clojure.source.dir}" />
  <property file="build.properties" />
  <property file="default.properties" />
  <path id="android.antlibs">
    <pathelement path="${sdk.dir}/tools/lib/anttasks.jar" />
    <pathelement path="${sdk.dir}/tools/lib/sdklib.jar" />
    <pathelement path="${sdk.dir}/tools/lib/androidprefs.jar" />
  </path>
  <taskdef name="setup"
    classname="com.android.ant.SetupTask"
    classpathref="android.antlibs" />
  <setup 
/>
</project>





       3) создаем local.property :
      sdk.dir=C:\Java\jdk1.6.0_18


   4) запускаем консоль и собираем проект командой ant

Для того чтобы проект не только собирался, но еще и обфусыровался, в папку с проектом нужно:
      5) настроить обфускацию в eclipse-e по инструкции

      6)  изменить local.property :
       sdk.dir=C:\Java\jdk1.6.0_18
       proguard.dir=C:\Progra~1\Android\android-sdk\tools\proguard
       key.store=my-release-key.keystore
       key.alias=alias_name
       key.store.password=12312312
       key.alias.password=12341234
   
      7) запускаем консоль и собираем проект командой ant release.

Для того, чтобы автоматически собрать проект для разных фирм, я создал jar файл, который
1) парсит файл, и достает оттуда данные
2) создает файл, размещает его в res/raw свой для каждой сборки
3) все, что в итоге собрано складывает в отдельную папку

Ниже я привожу исходники этого jar файла. Для того чтобы ими воспользоваться нужно
1) создать обычный java проект в eclipse
2) скопировать туда исходники, переделав соответственно под себя
3) командой file-> export-> runnable jar file получить jar файл
 
Исходники Main.java:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class Main {
  private static String RESOURCE_PATH = "res\\raw";
  private static ArrayList<TaxiCompany> taxiCompanies = new ArrayList<TaxiCompany>();
  private static String currentDirectory = new File(".").getAbsolutePath();
  static {
    currentDirectory = new File(".").getAbsolutePath();
  }
  public static void main(String[] args) {
    cleanFolder(currentDirectory + "\\" + "bin");
    cleanFolder(currentDirectory + "
\\" + "out");
    readAllTaxiCompanies();
    if (args != null) {
      for (int i = 0; i < taxiCompanies.size(); i++) {
        boolean removeCurrentCompany = true;
        for (int j = 0; j < args.length; j++) {
          if (taxiCompanies.get(i).getName().equals(args[j])) {
            removeCurrentCompany = false;
          }
        }
        if (removeCurrentCompany) {
          taxiCompanies.remove(i);
          i--;
        } else {
          buildAPK(taxiCompanies.get(i));
        }
      }
    }
 
    for (int i = 0; i < taxiCompanies.size(); i++) {
      copyFileToOutFolder(taxiCompanies.get(i).getName());
    }
  }

  private static void readAllTaxiCompanies() {
    String filePath = currentDirectory + "
\\" + "taxi_companies" + "\\" + "MobileTaxiMIDletClass.java";
    String str = null;
    try {
      BufferedReader in = new BufferedReader(new FileReader(filePath));
      TaxiCompany currentTaxiCompany = null;
      while ((str = in.readLine()) != null) {
        if (str.startsWith("
//#global")) {
          currentTaxiCompany.addLine(str);
        } else if (str.startsWith("//#_if (Dispatcher == \"")) {
String name = str.substring(22).replace("\"""").replace(")""").trim();
          currentTaxiCompany = new TaxiCompany(name);
          taxiCompanies.add(currentTaxiCompany);
        } else if (str.startsWith("//#_if(Dispatcher == \"")) {
          String name = str.substring(22).replace("\"""").replace(")""").trim();
          currentTaxiCompany = new TaxiCompany(name);
          taxiCompanies.add(currentTaxiCompany);
        }
      }
      in.close();
    } catch (IOException e) {
    }
  }

  private static void buildAPK(TaxiCompany taxiCompany) {
    String name = taxiCompany.getName();
    createNewFolderInFolderOut(name);
    changeBuildXML(name);
    String ip1 = taxiCompany.getIP1();
    String ip2 = taxiCompany.getIP2();
    String port = taxiCompany.getPort();
    String driverCanCancelOrder = String.valueOf( taxiCompany.getDriverCanCancelOrder() );
    String etherTogether = String.valueOf( taxiCompany.getEtherTogether() );
    String etherSortAboutTime = String.valueOf( taxiCompany.getEtherSortAboutTime() );
 
    try {
      File file = new File(RESOURCE_PATH + "\\" + "taxi_company_property.txt");
      file.createNewFile();
      FileWriter fstream = new FileWriter(file);
      BufferedWriter out = new BufferedWriter(fstream);
      out.write("
IP1:" + ip1 + "\n");
      out.write("
IP2:" + ip2 + "\n");
      out.write("
PORT:" + port + "\n");
      out.write("
driverCanCancelOrder:" + driverCanCancelOrder + "\n");
      out.write("
etherTogether:" + etherTogether + "\n");
      out.write("
etherSortAboutTime:" + etherSortAboutTime);
      out.flush();
      out.close();
      fstream.close();
      Runtime.getRuntime().exec("
cmd.exe /c start /wait /MIN " + "ant release");
      Thread.sleep(35000);
    } catch (Exception e) {
    }
  }

  private static void changeBuildXML(String companyName) {
    String buildXMLPath = "
build.xml";
    ArrayList<String> allLines = new ArrayList<String>();
     try {
      BufferedReader in = new BufferedReader(new FileReader(buildXMLPath));
      String str = null;
      while( (str=in.readLine()) != null) {
        allLines.add(str);
      }
      in.close();
   
      allLines.remove(1);
      allLines.add(1, "
<project name=\"" + companyName + "\" >");
      BufferedWriter out = new BufferedWriter(new FileWriter(buildXMLPath));
      for (int i = 0; i < allLines.size(); i++) {
        out.write(allLines.get(i) + "\n");
      }
      out.flush();
      out.close();
    } catch (Exception e) {}
  }

  private static void createNewFolderInFolderOut(String name) {
    File outFolder = new File(currentDirectory + "\\" + "out");
    outFolder.mkdir();
    File concreteTaxiCompanyFolder = new File(currentDirectory + "
\\" + "out" + "\\" + name);
    concreteTaxiCompanyFolder.mkdir();
  }

  private static void copyFileToOutFolder(String nameCompany) {
    String nameFile = nameCompany + "
-release.apk";
    String path1 = currentDirectory + "
\\" + "bin";
    String path2 = currentDirectory + "
\\" + "out" + "\\" + nameCompany;
    copy(path1 + "
\\" + nameFile, path2 + "\\" + nameFile);
  }

  private static void copy(String fromFileName, String toFileName) {
    try {
      File fromFile = new File(fromFileName);
      File toFile = new File(toFileName);
      if (toFile.isDirectory()) toFile = new File(toFile, fromFile.getName());

      if (toFile.exists()) {
        if (!toFile.canWrite())
          throw new IOException("
FileCopy: "
              + "
destination file is unwriteable: " + toFileName);
        System.out.print("
Overwrite existing file " + toFile.getName()
          + "
? (Y/N): ");
        System.out.flush();
        BufferedReader in = new BufferedReader(new InputStreamReader(
            System.in));
        String response = in.readLine();
        if (!response.equals("
Y") && !response.equals("y"))
          throw new IOException("
FileCopy: "
              + "
existing file was not overwritten.");
      } else {
      }

      FileInputStream from = null;
      FileOutputStream to = null;
      try {
        from = new FileInputStream(fromFile);
        to = new FileOutputStream(toFile);
        byte[] buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = from.read(buffer)) != -1)
          to.write(buffer, 0, bytesRead); // write
      } finally {
        if (from != null)
          try {
            from.close();
          } catch (IOException e) { }
          if (to != null)
            try {
              to.close();
            } catch (IOException e) { }
        }
      } catch (Exception e) { }
  }

  private static void cleanFolder(String path) {
    File folder = new File(path);
    String[] children = folder.list();
    for (int i=0; i<children.length; i++) {
      removeFolder(new File(folder, children[i]));
    }
  }

  private static void removeFolder(File folder) {
    if (folder.isDirectory()) {
      String[] children = folder.list();
      for (int i=0; i<children.length; i++) {
        removeFolder(new File(folder, children[i]));
      }
    }
    folder.delete();
  }

}





Исходники TaxiCompany.java:


public class TaxiCompany {

  private String _name = null;
  private int _numberLine = 0;

  private boolean _driverCanCancelOrder = true;
  private boolean _etherTogether = true;
  private boolean _etherSortAboutTime = true;
  private String _ip1;
  private String _ip2;
  private String _port;


  public TaxiCompany(String name) {
    _name = name;
  }

  public void addLine(String line) {
    if (_numberLine == 0) {
      _driverCanCancelOrder = Boolean.getBoolean( getValue(line) );
    } else if (_numberLine == 1) {
      _etherTogether = getValue(line).equals("0");
    } else if (_numberLine == 2) {
      _etherSortAboutTime = getValue(line).equals("0");
    } else if (_numberLine == 3) {
      _ip1 = getValue(line);
    } else if (_numberLine == 4) {
      _ip2 = getValue(line);
    } else if (_numberLine == 5) {
      _port = getValue(line);
    }
    _numberLine++;
  }

  public String getName() {
    return _name;
  }

  public boolean getDriverCanCancelOrder() {
    return _driverCanCancelOrder;
  }

  public boolean getEtherTogether() {
    return _etherTogether;
  }

  public boolean getEtherSortAboutTime() {
    return _etherSortAboutTime;
  }

  public String getIP1() {
    return _ip1;
  }

  public String getIP2() {
    return _ip2;
  }

  public String getPort() {
    return _port;
  }

  private String getValue(String line) {
    int index = line.indexOf("=");
    String result = line.substring(index+1, line.length()).replace("\"""").trim();
    return result;
  }
}



Для того чтобы выложить результат на ftp сервер(в моем случае на 2 фтп сервера):
1) дописал build.xml создав target:


<?xml version="1.0" encoding="UTF-8"?>
<project name="1616" >

  <property name="sdk.dir" location="C:\Progra~1\Android\android-sdk" />
  <property file="local.properties" />
  <property name="source.dir" value="src" />
  <property name="clojure.source.dir" value="src/clojure" />
  <property name="clojure.source.absolute.dir" location="${clojure.source.dir}" />
  <property file="build.properties" />
  <property file="default.properties" />

  <path id="android.antlibs">
    <pathelement path="${sdk.dir}/tools/lib/anttasks.jar" />
    <pathelement path="${sdk.dir}/tools/lib/sdklib.jar" />
    <pathelement path="${sdk.dir}/tools/lib/androidprefs.jar" />
  </path>

  <taskdef name="setup"
    classname="com.android.ant.SetupTask"
    classpathref="android.antlibs" />
  <setup />

  <target name="export">
    <ftp password="*****" server="****.***.**"
      userid="********"
      passive="true"
      remotedir="public/!android">
      <fileset dir="./out" />
    </ftp>
    <ftp password="*******" server="****.**.**"
      userid="*******"
      passive="true"
      remotedir="public/!android">
      <fileset dir="./out" />
    </ftp>
  </target>

</project>





2) скачал jar файл(apache commons), переименовал и разместил его в папке с проектом.
3) експорт осуществляется командой в консоли: ant export -lib export_to_ftp.jar


Итого я получил 2 bat файла, из которых 1 собирает проект, а 1-ой выкладывает его на ftp.


build.bat:

java -jar buildProject.jar
pause


export_to_ftp.bat:
ant export -lib export_to_ftp.jar





   








1 комментарий:

  1. Грамотно, спасибо!
    про сборку с помощью Ant еще вот это понравилось http://www.enterra.ru/blog/automation_builds_android_applications/

    ОтветитьУдалить