Zeyomir's Blog Bo piękniej jest wiedzieć coś o wszystkim…

20Gru/13Off
» «

Android i maven w jednym stali domu- część 2

Ok, w poprzedniej części powiedzieliśmy sobie jak zainstalować i skonfigurować mavena, wgraliśmy wszystkie wersje androida do lokalnego repo oraz dodaliśmy mavena do naszego androidowego projektu. W tym wpisie postaram się pokazać "po co nam to wszystko było". 

Dodawanie zależności

Po pierwsze- dodawanie nowych bibliotek jest teraz bajecznie proste. Szukamy interesującej nas biblioteki w interesującej nas wersji na mvnrepository.com i po prostu dodajemy znaleziony tam odpowiedni wpis w dependencies w naszym pliku pom.xml.

Biblioteka zostanie automatycznie pobrana i dołączona do projektu przy następnym wywołaniu mvn clean install. Co więcej, zostanie ona skopiowana do naszego lokalnego repo, dzięki czemu przy kolejnych buildach, albo gdy będziemy ją chcieli dołączyć do następnego projektu, nie będziemy jej już pobierać z internetu.

Na przykład aby dodać do naszego projektu genialną bibliotekę joda-time w najnowszej wersji, doklikamy się w końcu na stronę mvnrepository.com/artifact/joda-time/joda-time/2.3, a tam znajdziemy:

<dependency>
	<groupId>joda-time</groupId>
	<artifactId>joda-time</artifactId>
	<version>2.3</version>
</dependency>

Wklejamy to do naszego pom.xml pomiędzy tagi dependencies i gotowe- w IDE wystarczy dać 'reimport maven project' a biblioteka zostanie dołączona i będziemy mogli z niej korzytać.

I wszystko byłoby pięknie, ale... co zrobić, jeśli nie możemy znaleźć biblioteki której potrzebujemy w oficjalnym repo mavena?

Ręczne dodawanie bibliotek do lokalnego repozytorium mavena

Musimy sami dodać taką bibliotekę do lokalnego repozytorium. Są na to 3 sposoby:

  • jeśli biblioteka jest projektem mavenowym i rozpowszechniana jest wraz ze źródłami- wystarczy wejść do katalogu z biblioteką, wydać z konsoli mvn clean install i już mamy ją w naszym lokalnym repo. Możemy ją "zlokalizować" używając groupId, artifactId i version z pliku pom.xml biblioteki.
  • jeśli biblioteka jest rozpowszechniana ze źródłami, ale nie jest projektem mavenowym- tutaj sprawa jest cięższa, możemy spróbować zmienić ją w projekt mavenowy i postąpić tak jak w przypadku 1), ale wymaga to jako-takiej znajomości mavena, szczególnie jeśli biblioteka sama posiada jakieś zależności. Łatwiej potraktować ją tak jak w pkt 3).
  • jeśli biblioteka rozpowszechniana jest jako binarka (jar, apk, cokolwiek)- tu nie mamy dużego wyboru, pozostaje nam "ręcznie" zainstalować daną binarkę w naszym repo. Służy do tego polecenie
    mvn install:install-file 
        -Dfile=sciezka\do\pliku.jar 
        -DgroupId=com.glowny.pakiet
        -DartifactId=nazwa 
        -Dversion=wersja 
        -Dpackaging=jar
    

    Oczywiście "namierzamy ją" w swoim pom.xml używając podanego tu pakietu, nazwy i wersji.

Automatyczna zmiana ustawień/konfiguracji

Jeżeli trzymamy konfiguracje naszej aplikacji w plikach .properties (a jeśli nie- to powinniśmy), to możemy zautomatyzować zmianę tej konfiguracji w zależności od profilu w jakim budujemy aplikację. Przydatne, jeśli w aplikacji korzystamy z jakiegoś serwera/konta/kluczy api, które mają wersję testową i produkcyjną.

Wystarczy, że w pliku .properties zamiast standardowego

wlasciwosc=wartosc

wpiszemy takiego potworka:

wlasciwosc=${klucz}

a w naszym pom.xml dodamy do tagu project tag properties a w nim

<klucz>wartosc</klucz>

a w tagu build dodamy tag resources a w nim

<resource>
	<directory>src/main/resources</directory>
	<filtering>true</filtering>
</resource>

to przy budowaniu, klucz zostanie automatycznie zamieniony na wartość. Droga na około? Skądże! Przydatność tego rozwiązania widać dopiero gdy dodamy do niego profile. Do tagu project należy dodać

<profiles>
        <profile>
            <id>development</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <klucz1>wartosc dla dev 1</klucz1>
                <klucz2>wartosc dla dev 2</klucz2>
            </properties>
        </profile>

        <profile>
            <id>release</id>
            <properties>
                <klucz1>wartosc dla releasu 1</klucz1>
                <klucz2>wartosc dla releasu 2</klucz2>
            </properties>
        </profile>
</profiles>

Teraz domyślnie przy mvn clean install używane będą wartości z profilu development (oraz te które zadeklarowaliśmy wcześniej, a nie zostały nadpisane w tym profilu). Aby użyć wartości z profilu release wystarczy wykonać mvn clean install -Prelease.

Maven android plugin

Wszystko co pokazałem do tej pory to tak naprawdę podstawowe użycie mavena. Używając androidowego pluginu do mavena, możemy osiągnąć znacznie więcej.

Deployowanie

Wydając komendę mvn android:deploy zainstalujemy naszą aplikację na wszystkich dostępnych urządzeniach i emulatorach. Możemy oczywiście zbudować i zdeployować aplikację za jednym zamachem: mvn clean install android:deploy.

Podpisywanie

Możemy podpisać naszą aplikację naszym kluczem, tak żeby była gotowa do publikacji w google play. Należy w tym celu dodać konfigurację pluginu jar-signer:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jarsigner-plugin</artifactId>
    <version>1.2</version>
    <executions>
        <execution>
            <id>signing</id>
            <goals>
                <goal>sign</goal>
            </goals>
            <phase>package</phase>
            <inherited>true</inherited>
            <configuration>
                <archiveDirectory></archiveDirectory>
                <includes>
                    <include>target/*.apk</include>
                </includes>
                <keystore>sciezka/do/pliku/keystore</keystore>
                <storepass>haslo do keystora</storepass>
                <keypass>haslo klucza</keypass>
                <alias>nazwa klucza</alias>
                <arguments>
                    <argument>-sigalg</argument>
                    <argument>MD5withRSA</argument>
                    <argument>-digestalg</argument>
                    <argument>SHA1</argument>
                </arguments>
            </configuration>
        </execution>
    </executions>
</plugin>

Oczywiście możemy całość skonfigurować tak, żeby podpisywanie odbywało się tylko kiedy budujemy aplikację w profilu release. Mamy również możliwość automatycznej aktualizacji AndroidManifest.xml na podstawie ustawień z pom.xml (w tym automatyczne podbijanie wersji co build). Nie będę już tego opisywać, wszystko to można łatwo znaleźć w dokumentacji, zamieszczę jeszcze tylko "żywy przykład" wykorzystania tych dobroci w moim projekcie OCFun.

Przykład
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <properties>
        <version>0.7.0.0</version>

        <okapiOauthSecret>oauth secret</okapiOauthSecret>
        <okapiOauthKey>oauth key</okapiOauthKey>
        <debugMapsApiKey>debug maps api key</debugMapsApiKey>
        <!-- You won't need these if you are just running the app in emulator or on your own device -->
        <releaseMapsApiKey>release maps api key</releaseMapsApiKey>
        <keystorePath>path/to/keystore</keystorePath>
        <keystorePassword>keystore pass</keystorePassword>
        <keyAlias>alias</keyAlias>
        <keyPassword>key pass</keyPassword>
        <!-- You probably don't want to change these -->
        <sdk>19</sdk>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.zeyomir.ocfun</groupId>
    <artifactId>ocFun</artifactId>
    <version>${versionName}</version>
    <packaging>apk</packaging>
    <name>OpenCachingFun</name>

    <dependencies>
        <dependency>
            <groupId>android</groupId>
            <artifactId>android</artifactId>
            <version>4.4_r1</version>
            <scope>provided</scope>
        </dependency>

        <!-- Make sure this is below the android dependencies -->
        <dependency>
            <groupId>com.google.android.maps</groupId>
            <artifactId>maps</artifactId>
            <version>19_r1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.holoeverywhere</groupId>
            <artifactId>library</artifactId>
            <version>1.4.2</version>
            <type>apklib</type>
        </dependency>

        <dependency>
            <groupId>oauth.signpost</groupId>
            <artifactId>signpost-core</artifactId>
            <version>1.2.1.2</version>
        </dependency>
        <dependency>
            <groupId>oauth.signpost</groupId>
            <artifactId>signpost-commonshttp4</artifactId>
            <version>1.2.1.2</version>
        </dependency>
    </dependencies>

    <profiles>
        <profile>
            <id>development</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <versionName>${version}-SNAPSHOT</versionName>
                <incrementVersion>false</incrementVersion>
                <debuggable>true</debuggable>
                <mapsApiKey>${debugMapsApiKey}</mapsApiKey>
            </properties>
        </profile>

        <profile>
            <id>release</id>
            <properties>
                <versionName>${version}</versionName>
                <incrementVersion>true</incrementVersion>
                <debuggable>false</debuggable>
                <mapsApiKey>${releaseMapsApiKey}</mapsApiKey>
            </properties>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-jarsigner-plugin</artifactId>
                        <version>1.2</version>
                        <executions>
                            <execution>
                                <id>signing</id>
                                <goals>
                                    <goal>sign</goal>
                                </goals>
                                <phase>package</phase>
                                <inherited>true</inherited>
                                <configuration>
                                    <archiveDirectory></archiveDirectory>
                                    <includes>
                                        <include>target/*.apk</include>
                                    </includes>
                                    <keystore>${keystorePath}</keystore>
                                    <storepass>${keystorePassword}</storepass>
                                    <keypass>${keyPassword}</keypass>
                                    <alias>${keyAlias}</alias>
                                    <arguments>
                                        <argument>-sigalg</argument>
                                        <argument>MD5withRSA</argument>
                                        <argument>-digestalg</argument>
                                        <argument>SHA1</argument>
                                    </arguments>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>

                    <plugin>
                        <groupId>com.jayway.maven.plugins.android.generation2</groupId>
                        <artifactId>android-maven-plugin</artifactId>
                        <inherited>true</inherited>
                        <executions>
                            <execution>
                                <id>alignApk</id>
                                <phase>install</phase>
                                <goals>
                                    <goal>zipalign</goal>
                                </goals>
                            </execution>
                        </executions>
                        <configuration>
                            <sign>
                                <debug>false</debug>
                            </sign>
                            <zipalign>
                                <verbose>true</verbose>
                                <skip>false</skip>
                                <inputApk>${project.build.directory}/${project.artifactId}.apk</inputApk>
                                <outputApk>${project.artifactId}-aligned.apk</outputApk>
                            </zipalign>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>

    <build>
        <finalName>${project.artifactId}</finalName>
        <sourceDirectory>src/main/java</sourceDirectory>
        <plugins>
            <plugin>
                <groupId>com.jayway.maven.plugins.android.generation2</groupId>
                <artifactId>android-maven-plugin</artifactId>
                <version>3.6.0</version>
                <configuration>
                    <sdk>
                        <platform>${sdk}</platform>
                    </sdk>
                    <undeployBeforeDeploy>true</undeployBeforeDeploy>
                    <manifest>
                        <versionName>${versionName}</versionName>
                        <versionCodeAutoIncrement>${incrementVersion}</versionCodeAutoIncrement>
                        <versionCodeUpdateFromVersion>false</versionCodeUpdateFromVersion>
                        <debuggable>${debuggable}</debuggable>
                    </manifest>
                </configuration>
                <extensions>true</extensions>
                <executions>
                    <execution>
                        <goals>
                            <goal>manifest-update</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>

        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
</project>
app.versionName=${versionName}
okapi.oauthKey=${okapiOauthKey}
okapi.oauthSecret=${okapiOauthSecret}
googleMaps.apiKey=${mapsApiKey}
Bonus: debugowanie

Żeby podpiąć debugger do aplikacji uruchomionej przez mavena możemy zrobić tak jak opisano na wiki android-maven-plugin, albo (prościej) użyć przycisku 'attach debugger to android process' (przynajmniej w IntelliJ IDEA, jest w okolicach przycisku 'debug'). Jeśli potrzebujemy debugować proces uruchamiania aplikacji, należy aplikację uruchomić z adb shell. Wykonujemy w terminalu:

adb shell
am start -n com.yourapp/com.yourapp.YourActivity -D

W ten sposób aplikacja uruchomi się dopiero kiedy podłączymy się do niej z debuggerem.

» «
Tagged as: , Komentarze
Komentarze (0) Trackbacks (0)

Przepraszam, dodawanie komentarzy zablokowane.

Trackbacks are disabled.