Difference between revisions of "Android SDK"

From YobiWiki
Jump to navigation Jump to search
Line 495: Line 495:
 
/system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar:/system/framework/bouncycastle.jar -classpath /sdcard/CmdLine.jar %PACKAGE%.HelloWorld
 
/system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar:/system/framework/bouncycastle.jar -classpath /sdcard/CmdLine.jar %PACKAGE%.HelloWorld
 
</source>
 
</source>
  +
  +
'''UPDATE''': on Android 4.0.3 (ICS) it doesn't work anymore, I get an error
  +
java.lang.NoClassDefFoundError: org.bouncycastle.jce.provider.BouncyCastleProvider
   
 
===Using external BouncyCastle library from a simple java code===
 
===Using external BouncyCastle library from a simple java code===

Revision as of 22:57, 22 December 2011

Back to Android

Getting Android SDK

Online using Linux/Windows

Instructions below are for linux, if you're running Windows please check the provided resource links for variants of the instructions.
Make sure you've Java Development Kit installed

apt-get install sun-java6-jdk

For Windows get it here e.g. jdk-6u29-windows-x64.exe Warning at the moment JDK7 created some errors in the compilation process, better to use JDK6.

As explained above, get Android SDK from here, following those instructions
Run tools/android (or for Windows run SDK Manager) -> in installed packages make sure to have:

  • "Android SDK Tools", latest revision
  • "Android SDK Platform-tools", latest revision
  • a platform SDK, e.g. "Android 2.3.3"/"SDK Platform"
  • (Windows only) Extras / Google USB Driver (SDK Manager must be run as Admin on Win7) then follow instructions here


As we will develop from the command-line, no need for the Eclipse plugin
If you want to update SDK

  • tools/android update sdk
  • Then restart tools/android

Offline installation under Windows

If you are behind a proxy, you can configure SDK Manager (Tools/Options).
If you've no Internet connection at all, you need to download components on another computer.
To know where are the packages let's spy SDK Manager & its logs (small icon at bottom right)
Here is what I got with the versions of the moment:

Setting environment


We first define a number of things:

JAVA_HOME=/usr/lib/jvm/java-6-sun-1.6.0.26/
ANDROID_HOME=/path/to/your/android-sdk-linux_x86/
PACKAGE=com.foo.mytest1
PACKAGE_SLASH=${PACKAGE//.//}
DEV_HOME=$(pwd)/mytest

We need also to define the target. To know what are the available targets:

$ANDROID_HOME/tools/android list target
Available Android targets:
----------
id: 1 or "android-10"
    Name: Android 2.3.3
    Type: Platform
    API level: 10
    Revision: 2
    Skins: QVGA, WVGA854, HVGA, WQVGA432, WVGA800 (default), WQVGA400
    ABIs : armeabi

So here we'll define:

TARGET=android-10

Under Windows it'll look like

set JAVA_HOME="C:\Program Files\Java\jdk1.6.0_29"
set ANDROID_HOME="C:\Program Files (x86)\Android\android-sdk\"
set PACKAGE=com.foo.mytest1
set PACKAGE_SLASH=com/foo/mytest1
set PACKAGE_BACKSLASH=com\foo\mytest1
set DEV_HOME=C:\path\to\mytest
set TARGET=android-10

Note that I needed here to use absolute path for DEV_HOME otherwise I get errors with dx.exe

Preparing and using emulator

Here is how to create a basic emulator instance:

$ANDROID_HOME/tools/android --verbose create avd --name MyNexusS --target $TARGET --sdcard 1024M

Later, to launch it just do:

$ANDROID_HOME/tools/emulator -wipe-data -avd MyNexusS &

If needed to delete it:

$ANDROID_HOME/tools/android --verbose delete avd --name MyNexusS

Under Windows it'll look like:

%ANDROID_HOME%\tools\android --verbose create avd --name MyNexusS --target %TARGET% --sdcard 1024M
%ANDROID_HOME%\tools\emulator -wipe-data -avd MyNexusS
%ANDROID_HOME%\tools\android --verbose delete avd --name MyNexusS

Android application in command-line

See http://geosoft.no/development/android.html
Preparing the working directory (based on the environment variables defined above):

rm -rf $DEV_HOME
mkdir -p $DEV_HOME/src/$PACKAGE_SLASH/
mkdir -p $DEV_HOME/res/drawable/
mkdir -p $DEV_HOME/res/layout/
mkdir -p $DEV_HOME/res/values/
mkdir -p $DEV_HOME/obj/
mkdir -p $DEV_HOME/lib/
mkdir -p $DEV_HOME/bin/
mkdir -p $DEV_HOME/docs/

Create a dummy keystore:

$JAVA_HOME/bin/keytool -genkeypair \
                -validity 10000 \
                -dname "CN=company name,
                        OU=organisational unit,
                        O=organisation,
                        L=location,
                        S=state,
                        C=country code" \
                -keystore $DEV_HOME/AndroidTest.keystore \
                -storepass password \
                -keypass password \
                -alias AndroidTestKey \
                -keyalg RSA \
                -v

Create a Manifest file, here with some examples of permissions:

cat << EOF > $DEV_HOME/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="$PACKAGE"
      android:versionCode="1"
      android:versionName="1.0">

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

    <uses-sdk android:minSdkVersion="2"/>

    <application android:icon="@drawable/mylogo"
                 android:label="@string/myApplicationName">
        <activity android:name="$PACKAGE.HelloAndroid"
                  android:label="@string/myApplicationName">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
EOF

Provide source code of an app, here a simple HelloWorld, using an icon file some_icon.png:

cat << EOF > $DEV_HOME/src/$PACKAGE_SLASH/HelloAndroid.java
package $PACKAGE;

import android.app.Activity;
import android.content.res.Resources;
import android.os.Bundle;
import android.widget.TextView;

public class HelloAndroid extends Activity {

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    TextView textView = new TextView(this);

    String text = getResources().getString(R.string.helloText);
    textView.setText(text);

    setContentView(textView);
  }
}
EOF

cat << EOF > $DEV_HOME/res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="myApplicationName">Android Test Program</string>
    <string name="helloText">Hello, world!</string>
</resources>
EOF
cp some_icon.png $DEV_HOME/res/drawable/mylogo.png

Create R.java:

$ANDROID_HOME/platform-tools/aapt package -v -f -m \
    -S $DEV_HOME/res -J $DEV_HOME/src -M $DEV_HOME/AndroidManifest.xml \
    -I $ANDROID_HOME/platforms/$TARGET/android.jar || exit 1

Compile Java:

$JAVA_HOME/bin/javac -verbose -d $DEV_HOME/obj \
    -classpath "$ANDROID_HOME/platforms/$TARGET/android.jar:$DEV_HOME/obj" \
    -sourcepath $DEV_HOME/src \
    $DEV_HOME/src/$PACKAGE_SLASH/*.java || exit 1

Create DEX:

$ANDROID_HOME/platform-tools/dx --dex --verbose \
    --output=$DEV_HOME/bin/classes.dex \
    $DEV_HOME/obj $DEV_HOME/lib || exit 1

Create APK:

$ANDROID_HOME/platform-tools/aapt package -v -f \
    -S $DEV_HOME/res -M $DEV_HOME/AndroidManifest.xml \
    -I $ANDROID_HOME/platforms/$TARGET/android.jar \
    -F $DEV_HOME/bin/AndroidTest.unsigned.apk \
    $DEV_HOME/bin || exit 1

Sign APK:

$JAVA_HOME/bin/jarsigner -verbose \
    -keystore $DEV_HOME/AndroidTest.keystore \
    -storepass password \
    -keypass password \
    -signedjar $DEV_HOME/bin/AndroidTest.signed.apk \
    $DEV_HOME/bin/AndroidTest.unsigned.apk \
    AndroidTestKey || exit 1

Zip-align APK:

$ANDROID_HOME/tools/zipalign -v -f 4 \
    $DEV_HOME/bin/AndroidTest.signed.apk \
    $DEV_HOME/bin/AndroidTest.apk || exit 1

Generate documentation, if you wish:

$JAVA_HOME/bin/javadoc -verbose -d $DEV_HOME/docs -sourcepath $DEV_HOME/src \
    -classpath "$ANDROID_HOME/platforms/$TARGET/android.jar:$DEV_HOME/obj" \
    -author -package -use -splitIndex -version \
    -windowtitle 'AndroidTest' -doctitle 'AndroidTest' \
    $DEV_HOME/src/$PACKAGE_SLASH/*.java

To install the resulting application in the emulator (see above how to launch the emulator):

$ANDROID_HOME/platform-tools/adb -e install $DEV_HOME/bin/AndroidTest.apk

It's even possible to launch & control application from the PC.
See http://learnandroid.blogspot.com/2008/01/run-android-application-from-command.html

$ANDROID_HOME/platform-tools/adb -e shell am start -a android.intent.action.MAIN \
    -n $PACKAGE/$PACKAGE.HelloAndroid

To remove it:

$ANDROID_HOME/platform-tools/adb -e uninstall $PACKAGE

To do the same on a real device rather than on the emulator, make sure the phone is connected by USB and running in debug mode as explained above, then simple use -d (device) instead of -e (emulator), so previous instructions become:

$ANDROID_HOME/platform-tools/adb -d install $DEV_HOME/bin/AndroidTest.apk
$ANDROID_HOME/platform-tools/adb -d shell am start -a android.intent.action.MAIN \
    -n $PACKAGE/$PACKAGE.HelloAndroid
$ANDROID_HOME/platform-tools/adb -d uninstall $PACKAGE

Simple java code in command-line

See https://davanum.wordpress.com/2007/12/04/command-line-java-on-dalvikvm/

Not sure in which case you need it or not but it might be that you need:

  • a rooted phone
  • be root in shell as default (ro.secure=0 in the boot.img)


Preparing the working directory (based on the environment variables defined above):

rm -rf $DEV_HOME
mkdir -p $DEV_HOME/src/$PACKAGE_SLASH/
mkdir -p $DEV_HOME/obj/
mkdir -p $DEV_HOME/lib/
mkdir -p $DEV_HOME/bin/

Under Windows:

rmdir /S /Q %DEV_HOME%
mkdir %DEV_HOME%\src\%PACKAGE_BACKSLASH%\
mkdir %DEV_HOME%\obj\
mkdir %DEV_HOME%\lib\
mkdir %DEV_HOME%\bin\

Provide source code of an app, here a simple HelloWorld:

cat << EOF > $DEV_HOME/src/$PACKAGE_SLASH/HelloWorld.java
package $PACKAGE;

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}
EOF

Under Windows:
No idea how to script it, just copy the java code to a file %DEV_HOME%\src\%PACKAGE_BACKSLASH%\HelloWorld.java

Compile Java:

$JAVA_HOME/bin/javac -verbose -d $DEV_HOME/obj \
    -g $DEV_HOME/src/$PACKAGE_SLASH/*.java || exit 1

Under Windows:

%JAVA_HOME%\bin\javac -verbose -d %DEV_HOME%\obj ^
    -g %DEV_HOME%\src\%PACKAGE_BACKSLASH%\*.java

Create DEX:

$ANDROID_HOME/platform-tools/dx --dex --verbose \
    --output=$DEV_HOME/bin/classes.dex \
    $DEV_HOME/obj $DEV_HOME/lib || exit 1

Under Windows:

%ANDROID_HOME%\platform-tools\dx --dex --verbose ^
    --output=%DEV_HOME%\bin\classes.dex ^
    %DEV_HOME%\obj %DEV_HOME%\lib

Create JAR:

pushd $DEV_HOME/bin/
$ANDROID_HOME/platform-tools/aapt add $DEV_HOME/CmdLine.jar \
    classes.dex || exit 1
popd

Under Windows:

pushd %DEV_HOME%\bin\
%ANDROID_HOME%\platform-tools\aapt add %DEV_HOME%\CmdLine.jar ^
    classes.dex
popd

To install the resulting application in the emulator (see above how to launch the emulator):

$ANDROID_HOME/platform-tools/adb -e push $DEV_HOME/CmdLine.jar /sdcard/

Under Windows:

%ANDROID_HOME%\platform-tools\adb -e push %DEV_HOME%\CmdLine.jar /sdcard/

To execute it from the PC:

$ANDROID_HOME/platform-tools/adb -e shell \
    /system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar -classpath /sdcard/CmdLine.jar $PACKAGE.HelloWorld

Under Windows:

%ANDROID_HOME%\platform-tools\adb -e shell ^
    /system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar -classpath /sdcard/CmdLine.jar %PACKAGE%.HelloWorld

To do the same on a real device rather than on the emulator, make sure the phone is connected by USB and running in debug mode as explained above, then simple use -d (device) instead of -e (emulator), so previous instructions become:

$ANDROID_HOME/platform-tools/adb -d push $DEV_HOME/CmdLine.jar /sdcard/
$ANDROID_HOME/platform-tools/adb -d shell \
    /system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar -classpath /sdcard/CmdLine.jar $PACKAGE.HelloWorld

Under Windows:

%ANDROID_HOME%\platform-tools\adb -d push %DEV_HOME%\CmdLine.jar /sdcard/
%ANDROID_HOME%\platform-tools\adb -d shell ^
    /system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar -classpath /sdcard/CmdLine.jar %PACKAGE%.HelloWorld

BouncyCastle library

Depending on the creation of a real Android app or a simple java code and depending on the fact you want to use the internal crippled version or the full fledged version, different approaches are needed.
Internal library API is explained here
Some RSA examples are given here and a tuto (fr) here
To get a list of supported algorithms, see here. This illustrates e.g. the differences between the crippled internal version of the library and the complete one.

Using internal BouncyCastle library from an Android application

That's the normal way.
Here is an example, mixing the HelloAndroid shown above with an example from http://www.java2s.com/Tutorial/Java/0490__Security/RSASignatureGeneration.htm

cat << EOF > $DEV_HOME/src/$PACKAGE_SLASH/HelloAndroid.java
package $PACKAGE;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;

import android.app.Activity;
import android.content.res.Resources;
import android.os.Bundle;
import android.widget.TextView;

public class HelloAndroid extends Activity {

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    TextView textView = new TextView(this);

//    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

    try {
      KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", "BC");
      keyGen.initialize(512, new SecureRandom());

      KeyPair keyPair = keyGen.generateKeyPair();
      Signature signature = Signature.getInstance("SHA1withRSA", "BC");

      signature.initSign(keyPair.getPrivate(), new SecureRandom());

      byte[] message = "abc".getBytes();
      signature.update(message);

      byte[] sigBytes = signature.sign();
      signature.initVerify(keyPair.getPublic());
      signature.update(message);
      if (signature.verify(sigBytes))
        textView.setText("true");
      else
        textView.setText("false");
      setContentView(textView);
    } catch (java.security.NoSuchAlgorithmException e) {
      textView.setText("NoSuchAlgorithmException");
      setContentView(textView);
      return;
    } catch (java.security.NoSuchProviderException e) {
      textView.setText("NoSuchProviderException");
      setContentView(textView);
      return;
    } catch (java.security.InvalidKeyException e) {
      textView.setText("InvalidKeyException");
      setContentView(textView);
      return;
    } catch (java.security.SignatureException e) {
      textView.setText("SignatureException");
      setContentView(textView);
      return;
    }

  }
}
EOF

Using external BouncyCastle library from an Android application

Not tested. The problem is that it's impossible to get an external library with the exact same name as the internal one (see bugreport), so different approaches are possible:

Using internal BouncyCastle library from a simple java code


Here is an example, mixing the HelloWorld shown above with an example from http://www.java2s.com/Tutorial/Java/0490__Security/RSASignatureGeneration.htm

cat << EOF > $DEV_HOME/src/$PACKAGE_SLASH/HelloWorld.java
package $PACKAGE;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;

public class HelloWorld {

  public static void main(String[] args) throws Exception {
    //Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", "BC");

    keyGen.initialize(512, new SecureRandom());

    KeyPair keyPair = keyGen.generateKeyPair();
    Signature signature = Signature.getInstance("SHA1withRSA", "BC");

    signature.initSign(keyPair.getPrivate(), new SecureRandom());

    byte[] message = "abc".getBytes();
    signature.update(message);

    byte[] sigBytes = signature.sign();
    signature.initVerify(keyPair.getPublic());
    signature.update(message);
    System.out.println(signature.verify(sigBytes));
  }

}
EOF

There is a little trick when you will run the example on the phone or emulator: you've to provide explicitly the path to internal BouncyCastle:

$ANDROID_HOME/platform-tools/adb -d shell \
    /system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar:/system/framework/bouncycastle.jar -classpath /sdcard/CmdLine.jar $PACKAGE.HelloWorld

Under Windows:

%ANDROID_HOME%\platform-tools\adb -d shell ^
    /system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar:/system/framework/bouncycastle.jar -classpath /sdcard/CmdLine.jar %PACKAGE%.HelloWorld

UPDATE: on Android 4.0.3 (ICS) it doesn't work anymore, I get an error

java.lang.NoClassDefFoundError: org.bouncycastle.jce.provider.BouncyCastleProvider

Using external BouncyCastle library from a simple java code


You can use the same code as above but you need this time to provide the external library:

# From http://www.bouncycastle.org/latest_releases.html
cp -a bcprov-jdk16-146.jar $DEV_HOME/lib

To run the example, don't provide any path to the internal lib of course:

$ANDROID_HOME/platform-tools/adb -d shell \
    /system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar -classpath /sdcard/CmdLine.jar $PACKAGE.HelloWorld

Normally this works as such. In case of error no "BC" provider found, you can uncomment the line

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider())