Android Platform 3.0 SDK和Eclipse ADT安装记录二
?
(20120308补注)
注:从NDK r7开始引入了新的命令文件ndk-build.cmd,可以实现无cygwin的编译。使用它可以免除在Windows下手工写bat。但只适用于标准的JNI工程,如果要编译纯elf文件(main入口)仍然需要手工写Makefile或bat。下文中大多数都是基于NDK r5b的,可能已经过时,请留意。
?
(20120401补注)
注:从CDT Indigo SR2开始,CDT支持交叉编译的配置,下文中提到的CDT最初是基于旧版本的CDT?Galileo,相对会麻烦很多,而且不容易配置出正确的高亮着色和定义跳转。至于gdb的配置和使用是差不多的。请注意。另外,旧版本CDT可以使用GNU ARM的Ecllipse插件来简化配置操作。
?
目录:
一、简单地编写JNI及测试
二、ndk-gdb的使用
三、在CDT上看NDK工程(最好使用CDT Indigo SR2部署工程,见第十五节)
四、创建普通Android原生程序(main入口)
五、如何使用jdb调试android的java程序
六、利用Android NDK的Import Module功能导入C++的标准库(gnu-libstdc++)
七、main入口的c++程序编写(测试用)
八、依赖库问题
九、用Flash Builder 3.5开发Android的Air应用程序(模拟器上运行)
十、apk逆向工程
十一、adb使用摘要
十二、Android数据共享手段
十三、在App中运行原生可执行文件(elf格式)
十四、ListView的一些问题。
十五、用CDT?Indigo SR2创建main入口c工程
十六、Error generating final archive: Debug Certificate expired on ...的错误(转)
十七、刷新avd列表(重启adb服务器)
十八、查看内存占用量(检查内存泄露)
?
----------------
?
一、简单地编写JNI及测试:
?
(注:更快的方法是使用Ant和Eclipse,
见官网的介绍
http://developer.android.com/sdk/ndk/overview.html
?
首先用
>?..\..\ndk-build.cmd
生成libs\armeabi下的.so文件
然后原地创建Eclipse工程
?
Click File > New Android Project...
Select the Create project from existing source radio button.
Select any API level above Android 1.5.
In the Location field, click Browse... and select the <ndk-root>/samples/hello-jni directory.
Click Finish.
在创建Android工程的向导中有三项,第二项是从现存代码中创建(注意,必须按Browse按钮)
ADT会自动生成原来没有的许多工程文件。
不建议使用以下方法,因为从头再做一遍太麻烦了,而且容易出错!!!
)
?
1. 用bat文件设置JDK、Android SDK、ANT的路径,双击启动控制台。
?
@set PATH="C:\WINDOWS" @set PATH="C:\WINDOWS\system32";%PATH% @set PATH="D:\java\apache-ant-1.8.1\bin";%PATH% @set JAVA_HOME="D:\java\jdk1.6.0_20" @set PATH="D:\java\jdk1.6.0_20\bin";%PATH% @set PATH="D:\java\android-sdk_r10-windows\android-sdk-windows\platform-tools";%PATH% @set PATH="D:\java\android-sdk_r10-windows\android-sdk-windows\tools";%PATH% @cd /D "D:\java\android-sdk_r10-windows\android-sdk-windows\work" @cmd ?
?
?
2. 创建工程,并且测试(假设AVD的名称为add2)
?
> cd myjni
> ant
> ant debug
> android
(添加或检查已有AVD)
> start emualator -avd add2
> start adb logcat
(Ctrl+C退出)
> ant install
> adb shell pm list packages | find "myjni"
(看到package:com.example.myjni)
(打开模拟器,打开主菜单,选择MyJNIActivity,看到有一行文字
Hello World, MyJNIActivity
)
> ant uninstall
(关闭模拟器)
?
3. 加入JNI类,放入src\com\example\myjni目录中
?
?
package com.example.myjni;public class MyJNI { public static native int mycall(int x);}?
然后执行ant compile编译
?
4. 生成头文件,这里需要指定原生类class文件的根目录以及完整类名。
> javah -jni -classpath ./bin/classes -d jni com.example.myjni.MyJNI
输出文件为jni\com_example_myjni_MyJNI.h,内容如下:
?
?
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_example_myjni_MyJNI */#ifndef _Included_com_example_myjni_MyJNI#define _Included_com_example_myjni_MyJNI#ifdef __cplusplusextern "C" {#endif/* * Class: com_example_myjni_MyJNI * Method: mycall * Signature: (I)I */JNIEXPORT jint JNICALL Java_com_example_myjni_MyJNI_mycall (JNIEnv *, jclass, jint);#ifdef __cplusplus}#endif#endif?
由于使用JNIEXPORT进行导出,
所以在编译.so文件时编译器会检查此函数是否被实现。
(如果编译器看到这个头文件的内容)
?
5. 实现JNI接口。
创建jni目录。
创建一个.c文件,内容如下:
?
?
#include "com_example_myjni_MyJNI.h"#include <stdio.h>jint JNICALLJava_com_example_myjni_MyJNI_mycall(JNIEnv *env, jclass cl, jint x){ printf("hello, JNI, %d", x); return x + 1;}?
6. 编译JNI的.so文件(需要下载NDK,使用其中的工具链命令行,这里尽量用命令行)
方便起见,我没有使用官方提供的ndk-build,而是直接使用工具链命令行(可能有问题)。
?
(请尽量使用ndk-build和ndk-build.cmd,以节约时间和保证生成.so的正确性,以下步骤只是因为NDK r7之前还没有出现ndk-build.cmd工具)
?
> mkdir libs\armeabi
> C:/cygwin/home/Administrator/android-ndk-r5b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/arm-linux-androideabi-gcc.exe --sysroot="C:/cygwin/home/Administrator/android-ndk-r5b" -I"C:/cygwin/home/Administrator/android-ndk-r5b/platforms/android-8/arch-arm/usr/include" -L"C:/cygwin/home/Administrator/android-ndk-r5b/platforms/android-8/arch-arm/usr/lib" -o libs\armeabi\libMyJNI.so -shared jni/MyJNI.c
?
注意:上面的--sysroot应该是写错了,应该是类似这样才对
--sysroot=“C:/cygwin/home/Administrator/android-ndk-r5b/platforms/android-8/arch-arm”
见下面的Makefile。
?
输出文件名必须是lib前缀,.so后缀,而且必须输出到libs/armeabi目录下。
?
7. 在Activity中使用JNI,必须首先使用loadLibrary指定要加载的so文件名(不需要lib前缀和.so后缀)
?
?
package com.example.myjni;import android.app.Activity;import android.os.Bundle;public class MyJNIActivity extends Activity{ /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); int result = MyJNI.mycall(0); System.out.println("result is " + result); } static { System.loadLibrary("MyJNI"); }}?
8. 重新编译和打包apk
> ant clean debug
然后用7zip打开bin\MyJNI-debug.apk,查看libs\armeabi\libMyJNI.so是否被打包
?
9. 在模拟器内测试(方法同2),adb logcat的输出如下:
?
?
D/dalvikvm( 117): GC_EXPLICIT freed 2501 objects / 136776 bytes in 251ms
W/InputManagerService( 58): Ignoring hideSoftInput of: com.android.internal.vi
[email protected]
I/ActivityManager( 58): Starting activity: Intent { act=android.intent.action.
MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.example.myjni
/.MyJNIActivity }
I/ActivityManager( 58): Start proc com.example.myjni for activity com.example.
myjni/.MyJNIActivity: pid=262 uid=10037 gids={1015}
D/dalvikvm( 262): Trying to load lib /data/data/com.example.myjni/lib/libMyJNI.
so 0x44ede258
D/dalvikvm( 262): Added shared lib /data/data/com.example.myjni/lib/libMyJNI.so
0x44ede258
D/dalvikvm( 262): No JNI_OnLoad found in /data/data/com.example.myjni/lib/libMy
JNI.so 0x44ede258, skipping init
I/System.out( 262): result is 1
I/ActivityManager( 58): Displayed activity com.example.myjni/.MyJNIActivity: 2
033 ms (total 2033 ms)
D/dalvikvm( 119): GC_EXPLICIT freed 1177 objects / 85560 bytes in 95ms
D/dalvikvm( 171): GC_EXPLICIT freed 2990 objects / 179416 bytes in 105ms
D/dalvikvm( 195): GC_EXPLICIT freed 3071 objects / 178608 bytes in 103ms
可以看到:
* dalvikvm加载libMyJNI.so成功,
* 发现JNI_OnLoad不存在,自动跳过。
* System.out输出1,证明执行了MyJNI.mycall。
* .c文件内的printf没有产生任何输出。(不解,可能是.so编译过程有问题)
* 按后退键,然后重新启动活动,执行MyJNI.mycall。
* 按Home键,然后重新启动活动,不执行MyJNI.mycall。
?
10. 更多信息请参考官方的介绍或其它资料:
* http://developer.android.com/guide/practices/design/jni.html
* http://stackoverflow.com/questions/5123564/use-ant-build-xml-to-compile-jni-directory
* Android NDK的文档和示例。
?
----------------
20111025:
?
二、ndk-gdb的使用:(这里用官方提供的原生活动例子,所以需要Level 10的模拟器)
?
修改AndroidManifest.xml,添加可调试标签:
android:debuggable="true"
?
?
<?xml version="1.0" encoding="utf-8"?><!-- BEGIN_INCLUDE(manifest) --><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.native_activity" android:versionCode="1" android:versionName="1.0"> <!-- This is the platform API where NativeActivity was introduced. --> <uses-sdk android:minSdkVersion="10" /> <!-- This .apk has no Java code itself, so set hasCode to false. --> <application android:label="@string/app_name" android:hasCode="false" android:debuggable="true"> <!-- Our activity is the built-in NativeActivity framework class. This will take care of integrating with our NDK code. --> <activity android:name="android.app.NativeActivity" android:label="@string/app_name" android:configChanges="orientation|keyboardHidden"> <!-- Tell NativeActivity the name of or .so --> <meta-data android:name="android.app.lib_name" android:value="native-activity" /> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application></manifest> <!-- END_INCLUDE(manifest) -->
?
然后必须重新编译JNI工程(使用ndk-build clean all)和Android工程(使用ant clean debug)
如果缺少一个,都无法使用ndk-gdb调试
(官方NDK文档说可以在编译时使用
$NDK/ndk-build NDK_DEBUG=1
就不需要修改AndroidManifest.xml文件了
)
?
?
启动模拟器
> start emulator -avd <AVD名称>
?
启动ndk-gdb并启动程序(程序未启动)
?
?
或,启动ndk-gdb并依附到程序(程序已启动)
?
?
启动会话后ndk-gdb会自动暂停程序,出现>提示符,输入
> l
查看主文件的内容(或直接用编辑器查看)
以选择合适的断点行号或函数名,然后用
> b <断点地址,行号或函数名>
添加断点,
然后输入
> c
继续执行程序。
当断点命中时,可以用
> bt
查看回溯堆栈信息,
或使用其它gdb指令查看当前的变量值。
?
?
-----------------------------
三、在CDT上看NDK工程:(最好使用CDT Indigo SR2部署工程,见第十五节??)
?
?
1. 安装JRE(或JDK)以及CDT
JDK :?
http://www.oracle.com/technetwork/java/javase/downloads/index.html
Eclipse IDE for C/C++ Developers :
http://www.eclipse.org/downloads/
2. 创建C Makefile工程
File->New->Project...->C/C++->C Project
->(cancel) Use default location :?
不带空格,而且是新的子目录(需要自己添加)
->Makefile proejct->Empty->Cross GCC
3. 把工程的文本编码修改为UTF-8
Project->Properties->
Resource->Text file encoding->Other:?
-> UTF-8
4. 取消cygwin构建工具的本地化(避免中文乱码)
Project->Properties->
C/C++ Build->Environment->Add... :?
-> Name:LANG, Value:en_US.UTF-8
-> Name:PATH, Value:C:\cygwin\bin
(默认不会覆盖原有的环境变量,而是尾加,
所以需要按Edit把C:\cygwin\bin放到PATH的最前面,
避免编译时PATH查找到别的目录中)
5. 修改构建工具
Project->Properties->
C/C++ Build->Builder Settings
-> (cancel) Use default build command
-> Build command: bash -c /cygdrive/C/cygwin/home/Administrator/android-ndk-r5b/ndk-build
(根据实际路径设置ndk-build的cygdrive绝对路径)
6. 修改头文件自动检测命令
Project->Properties->
C/C++ Build->Discovery Options
-> Compiler invocation command
-> C:\cygwin\home\Administrator\android-ndk-r5b\toolchains\arm-linux-androideabi-4.4.3\prebuilt\windows\bin\arm-linux-androideabi-gcc.exe
根据NDK工具链的实际位置进行修改。
重启CDT后,Project Explorer会出现Includes目录。
多次修改可能无法生效(CDT的自动检测有问题?)
由于检测数据放在<workspace>\.metadata\.plugins\org.eclipse.cdt.make.core目录下
如果要修改这个设置,可以删除此目录,
然后重启CDT,强制使其重新执行检测命令,
扫描新的头文件目录。
7. 测试make
Project->Clean...
输出内容如下:
bash -c /cygdrive/C/cygwin/home/Administrator/android-ndk-r5b/ndk-build clean?
cygwin warning:
? MS-DOS style path detected: D:\ugame_c\native_activity
? Preferred POSIX equivalent is: /cygdrive/d/ugame_c/native_activity
? CYGWIN environment variable option "nodosfilewarning" turns off this warning.
? Consult the user's guide for more details about POSIX paths:
? ? http://cygwin.com/cygwin-ug-net/using.html#using-pathnames
/cygdrive/C/cygwin/home/Administrator/android-ndk-r5b/build/core/build-local.mk:85: *** Android NDK: Aborting ? ?. ?Stop.
Android NDK: Could not find application project directory ! ? ?
Android NDK: Please define the NDK_PROJECT_PATH variable to point to it. ? ?
说明ndk-build运行正常(因为目录中没有包含AndroidManifest.xml和JNI源代码)
8. 加入代码
复制示例代码
<NDK目录>/samples/native-activity
到Eclipse的工程树下
然后重新执行Project->Clean...
进行编译,输出如下:
?
?
bash -c /cygdrive/C/cygwin/home/Administrator/android-ndk-r5b/ndk-build clean
cygwin warning:
MS-DOS style path detected: D:\ugame_c\native_activity
Preferred POSIX equivalent is: /cygdrive/d/ugame_c/native_activity
CYGWIN environment variable option "nodosfilewarning" turns off this warning.
Consult the user's guide for more details about POSIX paths:
http://cygwin.com/cygwin-ug-net/using.html#using-pathnames
Compile thumb : native-activity <= main.c
Compile thumb : android_native_app_glue <= android_native_app_glue.c
StaticLibrary : libandroid_native_app_glue.a
SharedLibrary : libnative-activity.so
Install : libnative-activity.so => libs/armeabi/libnative-activity.so
**** Build Finished ****
?
9. 纠正代码错误提示的问题
由于CDT的错误提示不依赖于编译过程(即编译通过,编辑器仍会显示错误)
需要手动指定NDK工具链的头文件目录:
Project->Properties->
C/C++ Build->Paths and Symbols->Includes->GNU C->Add...
-> C:\cygwin\home\Administrator\android-ndk-r5b\platforms\android-9\arch-arm\usr\include
-> C:\cygwin\home\Administrator\android-ndk-r5b\sources\android\native_app_glue
(需要根据实际目录添加)
确定后CDT会自动刷新工程,重新检查错误。
?
-------------------
?
?
?
四、创建普通Android原生程序(main入口):
?
方法类似上面创建原生活动的方法,不同的是:
1. Make命令改为
bash -c /cygdrive/C/cygwin/bin/make
2. 创建源文件文件
File->New->Source File
->Source file : hello.c
编辑内容如下:
?
?
#include <stdio.h>int main(int argc, char **argv) { printf("Hello, world!\n"); return 0;}?
3. 创建Makefile
File->New->Other->General->File
->File name: Makefile
编辑内容如下:(绝对路径根据实际修改)
?
?
NDK_HOME := C:/cygwin/home/Administrator/android-ndk-r5bCC := /cygdrive/C/cygwin/home/Administrator/android-ndk-r5b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/arm-linux-androideabi-gccCC += --sysroot=$(NDK_HOME)/platforms/android-9/arch-armRM := rm -rfCFLAGS := -gCFLAGS += -I $(NDK_HOME)/platforms/android-9/arch-arm/usr/includeLIBS := -lmTARGET := helloOBJS := hello.oall : $(TARGET)$(TARGET) : $(OBJS) $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)%.o : %.c $(CC) $(CFLAGS) -o $@ -c $< clean : $(RM) $(OBJS) $(TARGET)?
4. 重新编译
然后按Project->Clean...重新编译,左面工程树出现Binaries和Includes节点。
5. 上传到模拟器并测试
启动emulator后,
> adb shell
# mkdir /data/hellowolrd
# exit
(创建可写目录)
> adb push hello /data/helloworld
(把刚才编译的文件上传至模拟器)
> adb shell
# cd /data/helloworld
# ls
# chmod 744 hello
# ./hello
Hello, world!
# exit
6. 远程调试
gdbserver的用法如下:
# gdbserver --help
gdbserver --help
Usage: ?gdbserver COMM PROG [ARGS ...]
? ? ? ? gdbserver COMM --attach PID [--close-fd FD]
?
COMM may either be a tty device (for serial debugging), or
HOST:PORT to listen for a TCP connection.
?
Exiting
如果要执行远程调试,可以
> start adb shell?
# cd /data/helloworld
# gdbserver :5039 ./hello
gdbserver :5039 ./hello
Process ./hello created; pid = 293
Listening on port 5039
(此时gdbserver未被连接,所以被阻塞)
然后重定向端口(详细见gdb help)
? adb forward <local> <remote> - forward socket connections
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?forward specs are one of:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?tcp:<port>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?localabstract:<unix domain socket name>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?localreserved:<unix domain socket name>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?localfilesystem:<unix domain socket name>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?dev:<character device name>
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?jdwp:<process pid> (remote only)
方法如下:
> adb forward tcp:5039 tcp:5039
这样模拟器的监听的模拟器端口5039,被重定向到宿主机的端口5039(只需要做一次)
然后启动本地的gdb
> C:\cygwin\home\Administrator\android-ndk-r5b\toolchains\arm-linux-androideabi-4.4.3\prebuilt\windows\bin\arm-linux-androideabi-gdb.exe
进入gdb后
(gdb) file hello
(加载elf文件的调试信息)
(gdb) target remote localhost:5039
(连接到本机的5039端口)
(gdb) b main
(下断点)
(gdb) c
(继续)
Continuing.
Error while mapping shared library sections:
/system/bin/linker: No such file or directory.
Error while mapping shared library sections:
libc.so: No error.
Error while mapping shared library sections:
libm.so: No error.
?
Breakpoint 1, main (argc=1, argv=0xbe9c5cd4) at hello.c:4
4 ? ? ? ? ? ? ? printf("Hello, world!\n");
(断点命中,用其它gdb指令调试)
(gdb) printf "%s\n", argv[0]
./hello
(输出argv[0]的字符串值,当前为./hello)
(gdb) bt
#0 ?main (argc=1, argv=0xbe9c5cd4) at hello.c:4
(回溯堆栈)
(gdb) n
(步进,gdbserver的控制台出现如下输出:
gdb: Unable to get location for thread creation breakpoint: requested event is n
ot supported
Hello, world!
)
7. 在CDT中执行gdb
原理和上面用命令行调试一样,但断点的触发不能关联到编辑器(未解决)
设置方法是
启动gdbserver后
打开CDT的Run->Debug Configurations->双击新建C/C++ Attach to Application->Debugger
-> Debugger : gdbserver
-> Main -> GDB debugger : C:\cygwin\home\Administrator\android-ndk-r5b\toolchains\arm-linux-androideabi-4.4.3\prebuilt\windows\bin\arm-linux-androideabi-gdb.exe
-> Connection -> Port Number : 5039
(设置好gdb绝对路径和端口号,按Apply和Debug)
Console视图会出现gdb的控制台(看右上角按钮Display Selected Console),可以输入相应的gdb命令。
不同于控制台调试,
1) gdb命令没有(gdb)提示符
2) gdb命令用绿色高亮显示
由于CDT的原因,断点触发时无法自动打开源文件。
?
---------------------------
?
?
五、如何使用jdb调试android的java程序
http://blog.csdn.net/dlmu2001/article/details/6946830
(未测试)
?
?
?
---------------------------
?
六、利用Android NDK的Import Module功能导入C++的标准库(gnu-libstdc++)
?
默认NDK不支持C++标准库,但提供Import Module功能
支持外挂的第三方移植库,
例如samples\native-activity就是在Android.mk中使用
LOCAL_STATIC_LIBRARIES := android_native_app_glue
和
$(call import-module,android/native_app_glue)
导入
$(NDK)/sources/android/native_app_glue
的第三方库
所以,可以用相同的方法导入
$(NDK)/sources/cxx-stl/gnu-libstdc++
?
例如:
?
# Copyright (C) 2009 The Android Open Source Project## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.#LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := libgl2jniLOCAL_CFLAGS := -WerrorLOCAL_SRC_FILES := gl_code.cpp LOCAL_LDLIBS := -llog -lGLESv2LOCAL_STATIC_LIBRARIES := gnustl_static# see http://stackoverflow.com/questions/7209971/ndk-build-undefined-reference-to-errors-when-statically-linking-to-libxml-a# 避免以下错误:# undefined reference to `std::__throw_bad_alloc()'LOCAL_ALLOW_UNDEFINED_SYMBOLS := trueinclude $(BUILD_SHARED_LIBRARY)$(call import-module,cxx-stl/gnu-libstdc++)
?
其中?
?
$(call import-module,cxx-stl/gnu-libstdc++)
表示导入
$(NDK)/sources/cxx-stl/gnu-libstdc++
的头文件和库文件
而
?
LOCAL_STATIC_LIBRARIES := gnustl_static
?
表示导入的模块名(必需)
模块名定义在
$(NDK)/sources/cxx-stl/gnu-libstdc++/Android.mk
中:
?
?
?
如果出现undefined reference to `std::__throw_bad_alloc()'错误
需要添加以下标志:
?
?
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
?
?
参见
http://stackoverflow.com/questions/7209971/ndk-build-undefined-reference-to-errors-when-statically-linking-to-libxml-a
?
--------------------------
?
七、main入口的c++程序编写(测试用)
?
假设有一个C++代码文件:
?
?
#include <iostream>using namespace std;int main(int argc, char *argv[]){ cout << "Hello, world!" << endl; return 0;}
?
编译用bat
?
?
C:/cygwin/home/Administrator/android-ndk-r5b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/bin/arm-linux-androideabi-g++ --sysroot=C:/cygwin/home/Administrator/android-ndk-r5b/platforms/android-8/arch-arm -L"C:/cygwin/home/Administrator/android-ndk-r5b/sources/cxx-stl/gnu-libstdc++/libs/armeabi" -L"C:/cygwin/home/Administrator/android-ndk-r5b/platforms/android-8/arch-arm/usr/lib" -I"C:/cygwin/home/Administrator/android-ndk-r5b/platforms/android-8/arch-arm/usr/include" -I"C:/cygwin/home/Administrator/android-ndk-r5b/sources/cxx-stl/gnu-libstdc++/include" -I"C:/cygwin/home/Administrator/android-ndk-r5b/sources/cxx-stl/gnu-libstdc++/libs/armeabi/include" hello.cpp -lc -lm -lstdc++ -o hello_cpppause?
上传和chmod 744的做法与前面关于c的hello,world程序编译步骤相同。
?
?
我测试过C++标准库中的vector,map,iostream和异常,代码如下(内附输出内容):
?
?
/*adb push hello_cpp /data/wmt*/#include <iostream>#include <vector>#include <map>using namespace std;int main(int argc, char *argv[]){ cout << "Hello, world!" << endl; vector<int> V; V.insert(V.begin(), 3); V[0] = 4; V[1] = 5; //越界 out of range cout << "size:" << V.size() << ",capacity:" << V.capacity() << endl; V.reserve(3); cout << "size:" << V.size() << ",capacity:" << V.capacity() << endl; cout << "V[0]:" << V[0] << endl; cout << "V[1]:" << V[1] << endl; map<const char*, int> months; months["january"] = 31; months["february"] = 28; months["march"] = 31; months["april"] = 30; months["may"] = 31; months["june"] = 30; months["july"] = 31; months["august"] = 31; months["september"] = 30; months["october"] = 31; months["november"] = 30; months["december"] = 31; cout << "june -> " << months["june"] << endl; try { throw "hello, exception!"; } catch (const char *&str) { cout << str << endl; } return 0;}/*# chmod 744 hello_cpp && ./hello_cppchmod 744 hello_cpp && ./hello_cppHello, world!size:1,capacity:1size:1,capacity:3V[0]:4V[1]:0june -> 30hello, exception!*/?
------------------------------------------------
八、依赖库问题:
?
E/AndroidRuntime(544): Caused by: java.lang.UnsatisfiedLinkError: Library XXX not found
------------------------------------------------
?
九、用Flash Builder 3.5开发Android的Air应用程序(模拟器上运行)
* 安装Flash Builder 3.5,创建一个Flex Mobile Project
* 右键->Export...->Flash Builder->Release Build
* 创建签名C:\Test\Test.p12文件,然后导出Test.apk
* 用adb install Test.apk安装,结果安装失败
Failure [INSTALL_FAILED_INVALID_APK]
(可能因为导出的apk使用了armeabi的.so不能装在模拟器上)
* 确保当前avd已经使用了sdcard(可以用edit按钮修改,但会丢失所有模拟器数据)
如果没有sdcard,后面运行air程序时会失败(adb logcat提示无法创建目录)。
* 用emulator -avd启动这个avd
* 用adb install(或adb install -s)安装C:\Program Files\Adobe\Adobe Flash Builder 4.5\sdks\4.5.0\runtimes\air\android\emulator\Runtime.apk
* 在Flex工程目录中写个bat文件,用adt创建自己的apk(指定目标为apk-emulator)
?
set path=C:\Program Files\Adobe\Adobe Flash Builder 4.5\sdks\4.5.0\bin;%path%cd bin-releasecall adt.bat -package -target apk-emulator -storetype pkcs12 -keystore C:\Test\Test.p12 ..\Test.apk Test-app.xml Test.swfcd ..pause
* 在模拟器内的settings中确保已经安装air(因为它不显示在启动器中)
* 用adb install重新安装生成的Test.apk
* 运行,成功
?
参考:
http://www.3amartstudio.com/blog/post/130.html
http://www.cnblogs.com/ginoz/archive/2011/01/26/1945074.html
http://help.adobe.com/en_US/air/build/WSfffb011ac560372f-5d0f4f25128cc9cd0cb-7ffe.html
?
?
(20120527)
如果用真机调试,SDK中AIR运行时的安装包
C:\Program Files\Adobe\Adobe Flash Builder 4.5\sdks\4.5.0\runtimes\air\android\device\Runtime.apk
只包含armeabi-v7a的.so文件,可能需要自己替换成
C:\Program Files\Adobe\Adobe Flash Builder 4.5\sdks\4.5.0\runtimes\air\android\emulator\Runtime.apk
否则运行会出错。
?
------------------------------------------------
十、apk逆向工程 / android hack技术
?
(TODO)
参考:
http://chuancun.sakura.ne.jp/mt/mt-search.cgi?IncludeBlogs=2&search=source%20code
(链接失效)
?
如何用gdb找到Android so文件中的加密key
http://all-ipad.net/how-to-get-key-from-android-so-using-gdb/
?
?
-------------------------------------------------
十一、adb使用摘要
(2012/03/13)
?
摘自android-ui-utils的design-preview:
http://code.google.com/p/android-ui-utils/
?
1. 运行应用程序的某个Activity
$ adb shell am start -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -n com.google.android.apps.proofer/.DesktopViewerActivity
?
2. 强制杀死应用程序
$ adb shell am force-stop com.google.android.apps.proofer
?
3. 卸载应用程序
$ adb uninstall com.google.android.apps.proofer
?
4. 安装apk到SD卡
$ adb install -r Proofer.apk
?
5. 重定向设备的监听端口到本机
$ adb forward tcp:<本地端口号如6800> tcp:<设备端口号如7800>
(Windows下测试)
> netstat -ano | find "6800"
> telnet localhost 6800
?
6. 搜索是否安装某个应用程序
$ adb shell pm list packages | grep com.google.android.apps.proofer
其它adb或android自带命令请参考:
http://en.androidwiki.com/wiki/ADB_Shell_Command_Reference
http://developer.android.com/guide/developing/tools/adb.html
?
?
十二、Android数据共享手段:
http://developer.android.com/resources/faq/framework.html
?
http://stackoverflow.com/questions/1636500/are-static-fields-in-activity-classes-guaranteed-to-outlive-a-create-destroy-cyc
?
http://stackoverflow.com/questions/2114312/android-persistent-state-with-global-variables-when-system-kills-activities
?
方法有(性能和适用的数据类型不一样,根据情况选择):
1.?Intent.putExtras()
2.?Preferences
3. 单例类getInstance()
?
?
class EvilSingleton{ private static EvilSingleton instance; //put your data as non static variables here public static EvilSingleton getInstance() { if(instance == null) instance = new EvilSingleton(); return instance; }}?
4.?public static字段/方法
5.?Long键WeakReference对象值的HashMap,传递Long键给另一个活动
6. 文件
7. 内容提供者
8. SQLite DB
9. 覆盖Application类
?
?
public class MyApplication extends Application{ private String thing = null; public String getThing(){ return thing; } public void setThing( String thing ){ this.thing = thing; }}public class MyActivity extends Activity { private MyApplication app; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); app = ((MyApplication)getApplication()); String thing = app.getThing(); }}
?
十三、在App中运行原生可执行文件(elf格式)
?
Run native executable in Android App
http://gimite.net/en/index.php?Run%20native%20executable%20in%20Android%20App
https://github.com/gimite/android-native-exe-demo
?
十四、ListView的一些问题
?
(1) ListView滚动时右侧快速滑块的启用方法
http://www.maxhis.info/archives/541
?
?
myListView.setFastScrollEnabled(true);
?
(2) 记录和恢复ListView滚动的位置
http://yes2.me/archives/567
?
?
//列表滚动private OnScrollListener ScrollLis = new OnScrollListener() { @Override public void onScroll(AbsListView arg0, int arg1, int arg2, int arg3) { } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if(scrollState==OnScrollListener.SCROLL_STATE_IDLE){ ListPos=list.getFirstVisiblePosition(); //ListPos记录当前可见的List顶端的一行的位置 } }};?
?
setOnScrollListener(ScrollLis);list.setSelection(ListPos);
?
十五、WebView的问题:
?
(1) JavaScript内定时器被触碰的输入事件阻塞
?
方法一:在JavaScript内解决。
参考:
http://www.html5rocks.com/en/mobile/touch/
?
?
clock();setInterval(clock, 1000);var touches = []document.body.addEventListener('touchmove', function(event) { event.preventDefault(); //关键在这一句 console.log("touchmove"); touches = event.touches;}, false);?
上面的touches数组可以传递给clock(),作为拖动信息读取。
?
方法二:在Java内屏蔽ACTION_MOVE,不过js端无法得到touchmove事件信息。
?
?
setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_MOVE) { return true; } return false; } });
?
?
?
十六、用CDT?Indigo SR2创建main入口c工程
?
配置步骤:
(0) CDT和NDK:
假设我的NDK目录是:
C:\cygwin\home\Administrator\android-ndk-r7b-windows\android-ndk-r7b\
CDT使用
Eclipse CDT Indigo Service Release 2(SR2支持创建交叉编译工程)
(1) 创建工程
Project name: test
File->New->C Project->
Executable->Cross-Compile Project->
Cross GCC
(2) 创建工程向导
Tool command prefix:?
arm-linux-androideabi-
Tool command path:
C:\cygwin\home\Administrator\android-ndk-r7b-windows\android-ndk-r7b\toolchains\arm-linux-androideabi-4.4.3\prebuilt\windows\bin
(3) 字符集
右键工程(注:在Project Explorer视图中,下同)->Properties->Resource
Text file encoding
选择Other: UTF-8
(4) make命令目录
Properties->C/C++ Build->
取消勾选Use default build command
Build command:
填入:
C:\cygwin\home\Administrator\android-ndk-r7b-windows\android-ndk-r7b\prebuilt\windows\bin\make?
(5) gcc参数设置
Properties->C/C++ Build->Settings->
Tool Settings->Cross GCC Compiler->Includes->
Include paths (-I)
添加:(带引号)
"C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/platforms/android-8/arch-arm/usr/include"
Tool Settings->Cross GCC Linker->Libraries->
Libraries (-l)
添加:
log
Library search path (-L)
添加:(带引号)
"C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/platforms/android-8/arch-arm/usr/lib"
Tool Settings->Cross GCC Linker->Miscellaneous->
Linker flags
填入:(带引号)
--sysroot="C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/platforms/android-8/arch-arm"
(6) 检查是否头文件目录正确:
按OK退出Properties后目录下的Includes节点出现三个目录:
C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/platforms/android-8/arch-arm/usr/include
C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/lib/gcc/arm-linux-androideabi/4.4.3/include
C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/windows/lib/gcc/arm-linux-androideabi/4.4.3/include-fixed
(7) 添加测试源文件
工程右键->New->Source File
Source file:填hello.c
Template:选择Default C source template
hello.c的内容如下:
?
?
/* * hello.c * * Created on: 2012-4-13 * Author: Administrator */#include <stdio.h>#include <android/log.h>#define TAG "HelloWorld"int main(int argc, char **argv) { printf("Hello, world!\n"); __android_log_print(ANDROID_LOG_INFO, TAG, "Hello, world!\n"); return 0;}?
?
(8) 开始编译:
工程右键->Build Project
弹出Build Project对话框,编译结束后消失。
出现Binaries节点和Debug目录
makefile文件生成在Debug目录下。
因为是调试版,所以Binaries节点中的"test - [arm/le]"可以展开
(9) 重新编译:
如果修改hello.c,但不编译,CDT仍然可以检查.c文件中的错误,
但Debug目录下的输出文件不会被修改。
重新编译可以有两种方法:
方法一、同(8),相当于执行make all
方法二、
Window->Show Views->Others->Make Target
打开Make Target视图
切换到test/Debug节点,然后按右上角加号按钮,
添加:clean all
然后双击clean all节点即可重新编译,
gcc编译器警告和错误信息输出在Problems视图中。
而make输出信息在Console视图的CDT Build Console中
(见视图右上角倒数第2个下拉菜单)
我的输出信息是:
?
?
?
**** Build of configuration Debug for project test ****
C:\cygwin\home\Administrator\android-ndk-r7b-windows\android-ndk-r7b\prebuilt\windows\bin\make clean all
rm -rf ./hello.o ./hello.d test
' '
'Building file: ../hello.c'
'Invoking: Cross GCC Compiler'
arm-linux-androideabi-gcc -I"C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/platforms/android-8/arch-arm/usr/include" -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"hello.d" -MT"hello.d" -o "hello.o" "../hello.c"
'Finished building: ../hello.c'
' '
'Building target: test'
'Invoking: Cross GCC Linker'
arm-linux-androideabi-gcc -L"C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/platforms/android-8/arch-arm/usr/lib" --sysroot="C:/cygwin/home/Administrator/android-ndk-r7b-windows/android-ndk-r7b/platforms/android-8/arch-arm" -o "test" ./hello.o -llog
'Finished building target: test'
' '
**** Build Finished ****
?
(10) gdbserver运行:
关于adb forward,上传二进制文件,gdbserver的运行的方法同前,略。
?
> start emulator -avd add2
> adb forward tcp:5039 tcp:5039
> adb shell
# mkdir /data/hello
> adb push test /data/hello
> adb shell
# cd /data/hello
# chmod 777 test
# gdbserver :5039 ./test
?
(11) gdb调试配置
Run->Debug Configurations
双击C/C++ Attach to Application添加一个配置
Main标签页设置
C/C++ Application: Debug\test
Project: test
Debugger标签页:
Debugger:
选择:
gdbserver
Debugger Options的Main页
GDB debugger:
填入:
C:\cygwin\home\Administrator\android-ndk-r7b-windows\android-ndk-r7b\toolchains\arm-linux-androideabi-4.4.3\prebuilt\windows\bin\arm-linux-androideabi-gdb.exe
GDB command file:
填入:
gdbinit.txt
Debugger Options的connection页
Type: TCP
Host name or IP address: localhost
Port number: 5039
工程右键->New->File
创建gdbinit.txt文件,内容如下:
?
?
file Debug/testb main?
?
然后按Debug连接gdbserver调试。
如果成功,Console视图可以直接输入gdb指令(会显示为绿色,同前,略)。
暂时没有办法在编辑器中加断点,也没有办法关联地打开源文件。
十六、Error generating final archive: Debug Certificate expired on ...的错误(转)
?
see
http://www.cnblogs.com/yyangblog/archive/2011/01/07/1929657.html
?
解决方法:
?
?
进入C:\Documents and Settings\Administrator\.android 删除路径下的debug.keystore及 ddms.cfg。
(不同环境下的目录可能略有不同,可在eclipse中查找此路径:Window->Preferences->Android->Build下 Default debug keystore)
然后重新导入即可。
?
?
?
(20120616)
十七、刷新avd列表(重启adb服务器)
> adb kill-server
> adb start-server
?
十八、查看内存占用量(检查内存泄露)
> ddms
选择一个进程,
然后按左上角show heap updates按钮(在Eclipse中则为DDMS切面Devices视图中的update heap按钮)
然后切换到右面的VM Heap,按Cause GC开始监控堆大小的改变(数值自动更新)
注意:如果是程序是多进程的,只显示其中一个进程的堆大小。其它进程要选择另一行。
?
?
(TODO)
?
?
?