Android Programming/ko

From Lazarus wiki
Revision as of 15:35, 12 July 2015 by FTurtle (talk | contribs)
Jump to navigationJump to search

English (en) 日本語 (ja) 한국어 (ko) русский (ru) 中文(中国大陆)‎ (zh_CN)

Custom Drawn Interface/Android도 보세요

일반적인 안드로이드 프로그래밍을 아는 것은 라자루스 안드로이드 인터페이스를 개발에 매우 유용하다.

방법...

NDK OpenGL 예제 빌드하기

다음 단계를 따르시요:

1 단계 - 안드로이드 NDK, 안드로이드 SDK 및 Ant.를 다운로드하고 설치하세요. 더 많은 정보는 다음에: 안드로이드 SDK와 에뮬레이터 및 폰을 사용한 안드로이드 인터페이스

2 단계 - 프리-컴파일 된 FPC 크로스-컴파일러를 설치한다. 설명은 이곳에: Android_Interface#Using_the_pre-compiled_compiler

3 단계 - 최신 라자루스 ccr소스포지 코드를 다운로드 한다:

svn co https://lazarus-ccr.svn.sourceforge.net/svnroot/lazarus-ccr lazarus-ccr

또는 만약 너무 크다고 생각한다면 lazarus-ccr/bindings/android-ndk 폴더만 다운로드하면 된다.

4 단계 - 파스칼 라이브러리를 빌드한다.

lazarus-ccr/bindings/android-ndk/examples/opengltest/opengltest.lpi 프로젝트를 연다.

Project->Project Options->Paths로 가서 "Libraries -Fl"이라고 쓰인 곳에서 이 값을 확인한다:

/home/felipe/Programas/android-ndk-r5/platforms/android-9/arch-arm/usr/lib

각자의 시스템에 있는 NDK와 최소 요구 안드로이드 API 레벨의 폴더를 가르키는 정확한 패스로 변경한다.

이제 라자루스에서 프로젝트를 빌드한다.

5 단계 - 빌드환경을 구성한다.

opengltest/local.propertie 파일을 열고 이 라인을 다음과 같이:

sdk.dir=/home/felipe/Programas/android-sdk-linux

이것을 SDK 위치로 변경한다.

6 단계 - APK를 빌드한다.

터미널을 역고 다음 명령을 입력한다:

cd lazarus-ccr/bindings/ndk/examples/opengltest/android ant debug

APK파일이 opengltest/android/bin/에 위치해 있을 것이다.

7 단계 - APK를 설치한다.

이 단계에서 퍼미션에 관한 에러가 발생하면 다음 글을 읽어라: 리눅스에서 장치의 인식

폰에서 APK를 설치하는 명령은:

cd opengltest/android
~/Programas/android-sdk-linux/platform-tools/adb install bin/OpenGLNDKTest-debug.apk 
2395 KB/s (107299 bytes in 0.043s)
       pkg: /data/local/tmp/OpenGLNDKTest-debug.apk
Success

이미 설치되어 있다는 에러 메세지가 나오면 다음 명령으로 설치할 수가 있다:

~/Programas/android-sdk-linux/platform-tools/adb uninstall com.pascal.opengltest

그리고 나서 새로이 추가된 아이콘을 통해 폰에서 실행하는 동안 무슨 로그가 있는지 알려면 adb logcat을 실행하면 된다:

~/Programas/android-sdk-linux/platform-tools/adb logcat

스크린 metrics 읽기

먼저 TDisplayMetrics에 정확한 정보를 넣는다:

uses androidutil;

var
  MyDisplayMetrics: TDisplayMetrics;
  Str: string;
  //
  lHeight, lWidth: Integer;
  xdpi, ydpi, lScreenSize: Single;
begin
  // ..
  // 객체

  MyDisplayMetrics := TDisplayMetrics.Create;
  Activity.getWindowManager().getDefaultDisplay().getMetrics(MyDisplayMetrics);

그리고 나면 TDisplayMetrics에 읽을 수 있다:

  lHeight := MyDisplayMetrics.heightPixels();
  lWidth := MyDisplayMetrics.widthPixels();
  xdpi := MyDisplayMetrics.xdpi();
  ydpi := MyDisplayMetrics.ydpi();
  lScreenSize := sqrt(sqr(lHeight / ydpi) + sqr(lWidth / xdpi));
  ldensity := MyDisplayMetrics.density();
  ldensityDpi := MyDisplayMetrics.densityDpi();
  scaledDensity := MyDisplayMetrics.scaledDensity();

많은 장치가 xdpi 와 ydpi가 다르다. 그러므로 위에서 계산한 lScreenSize 를 믿지마라. 스마트폰이 10 인치로 되어 있더라도, 정확한 값은 4 주변이다.

안드로이드 기기에 대한 세부사항

무척 많은 안드로이드 기기가 있이 때문에, 기기에 대한 몇가지 정보를 추적하는 것이 유용할 수 있다. 안드로이드 기기에 대해 위키피디아에서 비교한 [ http://en.wikipedia.org/wiki/Comparison_of_Android_devices] 것과[1]에 있는 프로세서의 자세한 명세를 읽어봐야 한다.

스마트폰

제조사 모델 안드로이드 API 이름 (빌드.모델) 프로세서 안드로이드 버전 멀티터치 기타
HTC Wildfire HTC Wildfire armv6 2.1=>2.2 Yes -
Sony Erricson Xperia X10 X10i armv7 1.6=>2.1 No -

태블릿

제조사 모델 안드로이드 API 이름 (빌드.모델) 프로세서 안드로이드 버전 멀티터치 기타
Toshiba Folio 100 Tablet TOSHIBA_FOLIO_AND_A armv7 2.2 Yes -

프로세서 호환(ARMv6 vs ARMv7) 순서에 따른 기기 리스트

ARMv7 기기리스트:

  • Advent Vega (P10AN01)
  • Dell Streak, Streak 7
  • HTC Desire
  • HTC Desire Z (T-Mobile G2)
  • HTC Desire HD
  • HTC Droid Incredible
  • HTC EVO 4G, EVO Shift 4G
  • HTC Glacier (T-Mobile myTouch 4G)
  • HTC Inspire 4G
  • HTC Nexus One
  • HTC Thunderbolt 4G
  • Huawei Ideos S7
  • LG Optimus Z
  • Motorola Atrix 4G
  • Motorola Bravo
  • Motorola Cliq 2 - untested
  • Motorola Defy
  • Motorola Droid 2, Droid 2 Global
  • Motorola Droid Pro (Motorola PRO)
  • Motorola Droid X
  • Motorola Xoom
  • POV Mobii Tegra Tablet
  • Samsung Continuum (i400)
  • Samsung Galaxy S (i9000, Captivate, Fascinate, Vibrant, Epic 4G)
  • Samsung Galaxy Tab
  • Sharp IS03
  • Sony Ericsson Xperia X10
  • Toshiba AS100
  • Viewsonic gTablet
  • Acer Liquid E
  • Acer Liquid (Liquid A1)
  • Archos 101 Internet Tablet
  • Motorola Charm
  • Motorola Droid (Milestone)
  • Samsung Galaxy S 4G
  • Samsung Nexus S

ARMv6 프로세서 리스트:

  • Android SDK 에뮬레이터
  • Asus Garmin nuvifone A50 (T-Mobile Garminfone)
  • Augen GENTouch 78 Tablet
  • Coby Kyros Internet Tablet (MID7015)
  • Geeksphone One, Geeksphone Zero
  • HTC Aria
  • HTC ChaCha
  • HTC Dream (T-Mobile G1, Android Dev Phone 1)
  • HTC Droid Eris
  • HTC Espresso (T-Mobile myTouch 3G Slide)
  • HTC Hero (T-Mobile G2 Touch)
  • HTC Legend
  • HTC Magic (T-Mobile myTouch 3G, T-Mobile G1 Touch)
  • HTC Salsa
  • HTC Tattoo
  • HTC Wildfire
  • Huawei Ascend
  • Huawei Ideos U8150-B (T-Mobile Comet)
  • Huawei U8110 (T-Mobile Pulse Mini)
  • Huawei U8230
  • LG Ally (Apex) (LG VS740)
  • LG GW620 (Eve, InTouch Max, LinkMe)
  • LG Optimus, Optimus M, Optimus T, Optimus S, Optimus V
  • LG Vortex
  • LG P500
  • MAG iMiTO iM7
  • vMAG iMiTO iM7S
  • Motorola Backflip
  • Motorola Citrus
  • Motorola Cliq (MB200)
  • Motorola Dext
  • Motorola Devour
  • Motorola i1
  • Motorola Spice XT300
  • Motorola Quench XT5 XT502
  • Pandigital Novel
  • Samsung GT-S5570 Galaxy Mini
  • Samsung i5500 Galaxy 5 (Corby)
  • Samsung i5700 Galaxy Portal (Spica)
  • Samsung i5800 Galaxy 3
  • Samsung i7500 Galaxy
  • Samsung Intercept
  • Samsung M900 Moment
  • Samsung S5830 Galaxy Ace
  • Samsung Transform
  • Sanyo ZIO M6000
  • Sony Ericsson Xperia X8
  • Sony Ericsson Xperia X10 Mini
  • Sony Ericsson Xperia X10 Mini Pro
  • Superpad 10.2" Tablet PC
  • Viewsonic ViewPad 7 Tablet
  • Velocity Micro T103 Cruz tablet
  • Vodafone 845
  • ZTE Blade

폰에서 사운드와 비디오 재생하기

각각의 폰은 서로 다른 코덱이 설치되어 있어서 네이티브 미디어플레이어가 폰에 따라 다른 포멧으로 플레이 할 수가 있다는 것을 의미한다. 다음은 각 폰의 네이티브 미디어 플레이어가 어떤 포맷을 플레이하는지 모여주는 표이다:

전화기 안드로이드 webm - VP8 m4v - H.264 ogv - Theora mp4 - H.264 mov - H.264 avi - RLE mpg - MPEG-1 wmv - WM9 3gp - MPEG-4
에뮬레이터 1.6 x x x x x x x x OK
에뮬레이터 2.1 x x x x x x x x OK
Nexus One 2.2 x OK x OK x x x x OK
HTC Desire 1.6 x OK x OK x x x OK OK
Toshiba Folio 100 2.2 x OK x OK x x x OK OK
Xperia X10 2.1 x OK x x x x x OK OK
Xperia X8 2.2 x OK x x x x x x OK
HTC Wildfire 2.1 x OK x x x x x x OK
HTC Desire HD 2.2 x OK x OK x x x x OK
Galaxy Tab 2.2 x OK x x x x x x OK
myPhone A210 1.6 x OK x x x x x x OK
Motorola Milestone 2.1 x OK x x x x x OK ?
Milestone 2 2.2 x OK x x x x x 사운드만 OK

안드로이드 파일 시스템

안드로이드는 어플리케이션이 데이터 디렉토리를 얻을 때 getApplicationContext().getFilesDir()의 사용을 추천하며 이 루틴은 HTC Wildfire에서는 /data/data/<패키지 명> 을 반환한다.

어플리케이션의 네이티브 라이브러리는 /data/data/<패키지>/lib 에 위치한다.

읽고 쓰고 새로운 파일을 생성하고 파일을 실행 시키기 좋은 곳은 /data/data/<패키지 명> 이다.

새로운 Java 어플리케이션의 생성

이 정보는 LCL-CustomDrawn-Android의 구현을 도와주는데 유용할 수 있다.

일반적인 설명은 이곳에 있다: http://developer.android.com/guide/developing/other-ide.html

가상 키보드를 보이고 / 숨기기

이곳을 보세요: http://android-codes-examples.blogspot.com/2011/11/show-or-hide-soft-keyboard-on-opening.html

나타내기:

InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,0);

키보드 감추기 위해서는:

InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(singleedittext.getWindowToken(),0);

안드로이드 JNI

JNI (Java Native Interface)를 사용하여 대부분의 안드로이드 SDK API들과 다른 Java 라이브러리를 호출 할 수 있다.

Java 타입과 파스칼 JNI 타입에 대한 표

인터페이스를 제외한 모든 Java 타입들은 JNI에서 문제없이 표시할 수 있다. 각각의 Java 타입에 대해 javaEnvRef^^.GetMethodID 과 같이 루틴에서 사용되는 VM 타입에 대응하는 것이 존재한다. 또한 JNI 네이티브 타입이 있으며, 이는 lazarus/lcl/interfaces/customdrawn/android/jni.pas 유닛에 선언되어 있고 파스칼로 작성된 JNI 코드에서 이용되는 타입이어야 한다. 파스칼에서 동등한 타입이 비교를 위해 제공 되며, JNI 코드를 작성할 때는 jni.pas 에서 선언된 타입이어야 한다.

Java Types VM 시그너쳐 jni.pas에서의 Types 파스칼에서 설명
boolean Z jboolean Boolean
byte B jbyte Byte
char C jchar Word
short S jshort Shortint
int I jint Integer
long J jlong Int64
float F jfloat Single
double D jdouble Double
a class, ie: String or InputStream L<full class name> ie: Ljava/lang/String; jobject N/A
Array, ie: int[] [<type-name> ie: [I N/A
A method type (arg-types)ref-type JMethodID N/A
void V N/A procedure

예제 1: Java 오브젝트를 생성하고 Java 메서드를 호출하기

다음 Java 코드에 대응하는 파스칼 JNI 코드를 원한다고 하자.

  HttpGet javaRequest = new HttpGet();
  URI myURI = new URI("http://magnifier.sourceforge.net/");
  javaRequest.setURI(myURI);

먼저 프로세스에 포함되는 모든 Class ID를 얻어야 한다. 그리고 나서 사용할 모든 메서드의 ID를 얻고 호출을 한다. 만약 호출이 파라메터를 가진다면, 배열로 전달한다. 다음 파스칼 네이티브 코드는 위의 Java 코드에 대응한다:

uses jni, customdrawnint;

var
  javaClass_HttpGet, javaClass_URI: jclass;
  javaMethod_HttpGet_new, javaMethod_HttpGet_setURI,
    javaMethod_URI_new: jmethodid;
  javaRequest, javaURI: jobject;
  javaString: jstring;
  lParams: array[0..2] of JValue;
  lNativeString: PChar;
begin
  DebugLn(':>LoadHTMLPageViaJNI');
  // 먼저 필요한 모든 클래스에 대하여 FindClass를 콜한다.
  javaClass_HttpGet := javaEnvRef^^.FindClass(javaEnvRef,
    'org/apache/http/client/methods/HttpGet');
  javaClass_URI := javaEnvRef^^.FindClass(javaEnvRef,
    'java/net/URI');

  // 이제 모든 메서드 ID를 얻는다
  DebugLn(':LoadHTMLPageViaJNI 1');
  javaMethod_HttpGet_new := javaEnvRef^^.GetMethodID(javaEnvRef, javaClass_HttpGet, '<init>', '()V');
  javaMethod_HttpGet_setURI := javaEnvRef^^.GetMethodID(javaEnvRef, javaClass_HttpGet, 'setURI', '(Ljava/net/URI;)V');
  javaMethod_URI_new := javaEnvRef^^.GetMethodID(javaEnvRef, javaClass_URI, '<init>', '(Ljava/lang/String;)V');

  // HTTP 응답 객체에 대한 새로운 인스턴스를 생성한다
  // HttpGet javaRequest = new HttpGet();
  javaRequest := javaEnvRef^^.NewObject(javaEnvRef,
    javaClass_HttpGet,
    javaMethod_HttpGet_new);

  DebugLn(':LoadHTMLPageViaJNI 4 javaRequest='+IntToHex(PtrInt(javaRequest), 8));
  // 응답 객체에 URI를 추가한다
  // URI javaURI = new URI("http://magnifier.sourceforge.net/");
  lParams[0].l := javaEnvRef^^.NewStringUTF(javaEnvRef, 'http://magnifier.sourceforge.net');
  javaURI := javaEnvRef^^.NewObjectA(javaEnvRef,
    javaClass_URI, javaMethod_URI_new, @lParams[0]);
  javaEnvRef^^.DeleteLocalRef(javaEnvRef, lParams[0].l);
  // javaRequest.setURI(javaURI);
  lParams[0].l := javaURI;
  javaEnvRef^^.CallVoidMethodA(javaEnvRef, javaRequest,
    javaMethod_HttpGet_setURI, @lParams[0]);

예제 2: 정적 메서드 호출

Bass 클래스에 있는 다음 정적 메서드를 호출하기를 원한다고 하자. http://jerome.jouvie.free.fr/nativebass/javadoc/org/jouvieje/bass/Bass.html

  public static native int BASS_StreamCreateFile(String file, long offset, long length, int flags);

먼저 프로세스에 포함된 모든 Class ID를 얻고 정적 메서드의 ID를 얻으며 배열과 함께 파라메터를 넣어 호출한다:

uses jni, customdrawnint;

var
  javaClass_Bass: jclass;
  javaMethod_Bass_BASS_StreamCreateFile: jmethodid;
  javaString: jstring;
  lParams: array[0..3] of JValue;
  lRetInt: jint;
begin
  // 먼저 필요한 모든 클래스에 대하여 FindClass를 콜한다.
  javaClass_Bass := javaEnvRef^^.FindClass(javaEnvRef, 'org/jouvieje/bass/Bass');

  //  모든 메서드 ID
  javaMethod_Bass_BASS_StreamCreateFile := javaEnvRef^^.GetStaticMethodID(javaEnvRef, javaClass_Bass, 'BASS_StreamCreateFile', '(Ljava/lang/String;JJI)I');

  // 호출한다.
  lParams[0].l := javaEnvRef^^.NewStringUTF(javaEnvRef, '/path/to/file');
  lParams[1].j := 0; // 오프셋
  lParams[2].j := 200; // 길이
  lParams[3].i := 0; // 플래그
  lRetInt := javaEnvRef^^.CallStaticIntMethodA(javaEnvRef, javaClass_Bass, javaMethod_Bass_BASS_StreamCreateFile, @lParams[0]);
  javaEnvRef^^.DeleteLocalRef(javaEnvRef, lParams[0].l);

참고