2013年1月27日 星期日

无Java开发Android应用(NativeActivity)

最新的 Android 2.3 无需 Java 就可以开发应用,详情请看 这里
这里是官方给的例子程序 ,来自:http://developer.android.com/reference/android/app/NativeActivity.html

代码片段(2)

[代码] AndroidManifest.xml

01<manifest xmlns:android="http://schemas.android.com/apk/res/android"
02        package="com.example.native_activity"
03        android:versionCode="1"
04        android:versionName="1.0">
05  
06    <!-- This is the platform API where NativeActivity was introduced. -->
07    <uses-sdk android:minSdkVersion="8" />
08  
09    <!-- This .apk has no Java code itself, so set hasCode to false. -->
10    <application android:label="@string/app_name" android:hasCode="false">
11  
12        <!-- Our activity is the built-in NativeActivity framework class.
13             This will take care of integrating with our NDK code. -->
14        <activity android:name="android.app.NativeActivity"
15                android:label="@string/app_name"
16                android:configChanges="orientation|keyboardHidden">
17            <!-- Tell NativeActivity the name of or .so -->
18            <meta-data android:name="android.app.lib_name"
19                    android:value="native-activity" />
20            <intent-filter>
21                <action android:name="android.intent.action.MAIN" />
22                <category android:name="android.intent.category.LAUNCHER" />
23            </intent-filter>
24        </activity>
25    </application>
26  
27</manifest>

[代码] Demo.c

001#include <jni.h>
002#include <errno.h>
003  
004#include <EGL/egl.h>
005#include <GLES/gl.h>
006  
007#include <android/sensor.h>
008#include <android/log.h>
009#include <android_native_app_glue.h>
010  
011#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
012#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))
013  
014/**
015 * Our saved state data.
016 */
017struct saved_state {
018    float angle;
019    int32_t x;
020    int32_t y;
021};
022  
023/**
024 * Shared state for our app.
025 */
026struct engine {
027    struct android_app* app;
028  
029    ASensorManager* sensorManager;
030    const ASensor* accelerometerSensor;
031    ASensorEventQueue* sensorEventQueue;
032  
033    int animating;
034    EGLDisplay display;
035    EGLSurface surface;
036    EGLContext context;
037    int32_t width;
038    int32_t height;
039    struct saved_state state;
040};
041  
042/**
043 * Initialize an EGL context for the current display.
044 */
045static int engine_init_display(struct engine* engine) {
046    // initialize OpenGL ES and EGL
047  
048    /*
049     * Here specify the attributes of the desired configuration.
050     * Below, we select an EGLConfig with at least 8 bits per color
051     * component compatible with on-screen windows
052     */
053    const EGLint attribs[] = {
054            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
055            EGL_BLUE_SIZE, 8,
056            EGL_GREEN_SIZE, 8,
057            EGL_RED_SIZE, 8,
058            EGL_NONE
059    };
060    EGLint w, h, dummy, format;
061    EGLint numConfigs;
062    EGLConfig config;
063    EGLSurface surface;
064    EGLContext context;
065  
066    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
067  
068    eglInitialize(display, 0, 0);
069  
070    /* Here, the application chooses the configuration it desires. In this
071     * sample, we have a very simplified selection process, where we pick
072     * the first EGLConfig that matches our criteria */
073    eglChooseConfig(display, attribs, &config, 1, &numConfigs);
074  
075    /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
076     * guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
077     * As soon as we picked a EGLConfig, we can safely reconfigure the
078     * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
079    eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
080  
081    ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);
082  
083    surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
084    context = eglCreateContext(display, config, NULL, NULL);
085  
086    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
087        LOGW("Unable to eglMakeCurrent");
088        return -1;
089    }
090  
091    eglQuerySurface(display, surface, EGL_WIDTH, &w);
092    eglQuerySurface(display, surface, EGL_HEIGHT, &h);
093  
094    engine->display = display;
095    engine->context = context;
096    engine->surface = surface;
097    engine->width = w;
098    engine->height = h;
099    engine->state.angle = 0;
100  
101    // Initialize GL state.
102    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
103    glEnable(GL_CULL_FACE);
104    glShadeModel(GL_SMOOTH);
105    glDisable(GL_DEPTH_TEST);
106  
107    return 0;
108}
109  
110/**
111 * Just the current frame in the display.
112 */
113static void engine_draw_frame(struct engine* engine) {
114    if (engine->display == NULL) {
115        // No display.
116        return;
117    }
118  
119    // Just fill the screen with a color.
120    glClearColor(((float)engine->state.x)/engine->width, engine->state.angle,
121            ((float)engine->state.y)/engine->height, 1);
122    glClear(GL_COLOR_BUFFER_BIT);
123  
124    eglSwapBuffers(engine->display, engine->surface);
125}
126  
127/**
128 * Tear down the EGL context currently associated with the display.
129 */
130static void engine_term_display(struct engine* engine) {
131    if (engine->display != EGL_NO_DISPLAY) {
132        eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
133        if (engine->context != EGL_NO_CONTEXT) {
134            eglDestroyContext(engine->display, engine->context);
135        }
136        if (engine->surface != EGL_NO_SURFACE) {
137            eglDestroySurface(engine->display, engine->surface);
138        }
139        eglTerminate(engine->display);
140    }
141    engine->animating = 0;
142    engine->display = EGL_NO_DISPLAY;
143    engine->context = EGL_NO_CONTEXT;
144    engine->surface = EGL_NO_SURFACE;
145}
146  
147/**
148 * Process the next input event.
149 */
150static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) {
151    struct engine* engine = (struct engine*)app->userData;
152    if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
153        engine->animating = 1;
154        engine->state.x = AMotionEvent_getX(event, 0);
155        engine->state.y = AMotionEvent_getY(event, 0);
156        return 1;
157    }
158    return 0;
159}
160  
161/**
162 * Process the next main command.
163 */
164static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
165    struct engine* engine = (struct engine*)app->userData;
166    switch (cmd) {
167        case APP_CMD_SAVE_STATE:
168            // The system has asked us to save our current state.  Do so.
169            engine->app->savedState = malloc(sizeof(struct saved_state));
170            *((struct saved_state*)engine->app->savedState) = engine->state;
171            engine->app->savedStateSize = sizeof(struct saved_state);
172            break;
173        case APP_CMD_INIT_WINDOW:
174            // The window is being shown, get it ready.
175            if (engine->app->window != NULL) {
176                engine_init_display(engine);
177                engine_draw_frame(engine);
178            }
179            break;
180        case APP_CMD_TERM_WINDOW:
181            // The window is being hidden or closed, clean it up.
182            engine_term_display(engine);
183            break;
184        case APP_CMD_GAINED_FOCUS:
185            // When our app gains focus, we start monitoring the accelerometer.
186            if (engine->accelerometerSensor != NULL) {
187                ASensorEventQueue_enableSensor(engine->sensorEventQueue,
188                        engine->accelerometerSensor);
189                // We'd like to get 60 events per second (in us).
190                ASensorEventQueue_setEventRate(engine->sensorEventQueue,
191                        engine->accelerometerSensor, (1000L/60)*1000);
192            }
193            break;
194        case APP_CMD_LOST_FOCUS:
195            // When our app loses focus, we stop monitoring the accelerometer.
196            // This is to avoid consuming battery while not being used.
197            if (engine->accelerometerSensor != NULL) {
198                ASensorEventQueue_disableSensor(engine->sensorEventQueue,
199                        engine->accelerometerSensor);
200            }
201            // Also stop animating.
202            engine->animating = 0;
203            engine_draw_frame(engine);
204            break;
205    }
206}
207  
208/**
209 * This is the main entry point of a native application that is using
210 * android_native_app_glue.  It runs in its own thread, with its own
211 * event loop for receiving input events and doing other things.
212 */
213void android_main(struct android_app* state) {
214    struct engine engine;
215  
216    // Make sure glue isn't stripped.
217    app_dummy();
218  
219    memset(&engine, 0, sizeof(engine));
220    state->userData = &engine;
221    state->onAppCmd = engine_handle_cmd;
222    state->onInputEvent = engine_handle_input;
223    engine.app = state;
224  
225    // Prepare to monitor accelerometer
226    engine.sensorManager = ASensorManager_getInstance();
227    engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
228            ASENSOR_TYPE_ACCELEROMETER);
229    engine.sensorEventQueue = ASensorManager_createEventQueue(engine.sensorManager,
230            state->looper, LOOPER_ID_USER, NULL, NULL);
231  
232    if (state->savedState != NULL) {
233        // We are starting with a previous saved state; restore from it.
234        engine.state = *(struct saved_state*)state->savedState;
235    }
236  
237    // loop waiting for stuff to do.
238  
239    while (1) {
240        // Read all pending events.
241        int ident;
242        int events;
243        struct android_poll_source* source;
244  
245        // If not animating, we will block forever waiting for events.
246        // If animating, we loop until all events are read, then continue
247        // to draw the next frame of animation.
248        while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, NULL, &events,
249                (void**)&source)) >= 0) {
250  
251            // Process this event.
252            if (source != NULL) {
253                source->process(state, source);
254            }
255  
256            // If a sensor has data, process it now.
257            if (ident == LOOPER_ID_USER) {
258                if (engine.accelerometerSensor != NULL) {
259                    ASensorEvent event;
260                    while (ASensorEventQueue_getEvents(engine.sensorEventQueue,
261                            &event, 1) > 0) {
262                        LOGI("accelerometer: x=%f y=%f z=%f",
263                                event.acceleration.x, event.acceleration.y,
264                                event.acceleration.z);
265                    }
266                }
267            }
268  
269            // Check if we are exiting.
270            if (state->destroyRequested != 0) {
271                engine_term_display(&engine);
272                return;
273            }
274        }
275  
276        if (engine.animating) {
277            // Done with events; draw next animation frame.
278            engine.state.angle += .01f;
279            if (engine.state.angle > 1) {
280                engine.state.angle = 0;
281            }
282  
283            // Drawing is throttled to the screen update rate, so there
284            // is no need to do timing here.
285            engine_draw_frame(&engine);
286        }
287    }
288}


資料來源    http://www.oschina.net/code/snippet_12_2904

Android混淆、反编译以及反破解的简单回顾

一、Android混淆
1)概述
         新建Android工程,根目录下会有个proguard.cfg。简单的混淆,你只需要在project.properties内加入一行“proguard.config=proguard.cfg”即可。
         注意:在签名发布apk时才会混淆,直接Run As在bin目录下的apk是不被混淆的。签名发布:右键工程->Android Tools->Export Signed Application Package…
         如何生成签名,可以参考《Android 数字签名学习笔记》。
 
2)外部jar
         未混淆过的,只加个类库声明就好。例如,用到“SDK目录\ extras\android\support\v4\ android-support-v4.jar”时,可以在-keep前加如下内容即可:
  1. -dontwarn android.support.** 
  2. -libraryjars lib/android-support-v4.jar 
         第一行,表示去除警告,第二行是声明jar(jar包拷到工程内了,所以是相对目录==)。
         这样混淆后,引用的jar包也会一起被混淆。
 
         如果用的第三方jar包是被混淆过的,或你不想混淆,则用-keep去除即可。例如,之前android-support-v4.jar,如果不需要混淆它的话,可以增加这么一句:
  1. -keep class android.support.v4.** { 
  2.         *; 
         此时的话,jar包就不会被混淆了^^。
 
         更详细的使用方法,请参看小节3。
 
1. 在手册的样例中,有两篇即是讲述Android的,如下:
         Manual->Examples->A simple Android activity&A complete Android application
2. 用法的内容,则在:Manual->Usage。用于学习或查看各命令都是做什么的用。
 
中文相关的话,可以参考下述网址,呼呼~
 
4)可能问题
4.1)新建工程下没有proguard.cfg
         你的环境太老了吧==。
         ProGuard是2.2才加的?记得我起初低于2.2的混淆时,要从2.2工程下把proguard.cfg拷过去。当时建2.1的目录下是没proguard.cfg的。
         不过现在建立个1.5都是有这个文件的。
 
二、Android反编译
1)概述
         apktool + dex2jar + jd-gui。超链接是主页,不了解的可以看看介绍,再转至Downloads。
 
         具体做什么用的或如何操作,参看小节2。
 
         当然,和之前《批处理安装&卸载apk》一样,小子懒人一个T^T。又是批处理(没sh的……):
easyTool.bat
  1. @echo off 
  2. title APK反编译[by Join
  3.  
  4. rem apktool目录 
  5. set p_at="E:\zhao\environment\decompile\apktool" 
  6. rem dex2jar目录 
  7. set p_dj="E:\zhao\environment\decompile\dex2jar-0.0.9.8" 
  8. rem dex2jar后缀 
  9. set suffix=_dex2jar.jar 
  10.  
  11. if "%~1"=="" echo 请将apk直接拖放至bat文件!&goto :over 
  12.  
  13. rem 增加apktool路径 
  14. set path=%p_at%;%p_dj%;%path% 
  15.  
  16. setlocal enabledelayedexpansion 
  17. if /i "%~x1"==".apk" ( 
  18.   echo apktool处理"%~nx1"中... 
  19.   apktool d "%~1" "%~dpn1" 
  20.   echo dex2jar处理"%~nx1"中... 
  21.   dex2jar.bat "%~1" 
  22.   rem dex2jar执行后直接结束了== 
  23.   echo 移动文件"%~n1!suffix!"中... 
  24. else ( 
  25.   echo 文件类型错误:不支持%~x1! 
  26.  
  27. :over 
  28. echo. 
  29. @pause>nul 
         保存成bat,修改下apktool目录&dex2jar目录,将apk拖上去即可。会有一个“同名”文件夹和一个“同名_dex2jar.jar”的文件。文件夹是apktool生成的资源,jar则是dex2jar反编译出的代码。然后用jd-gui打开jar即可。
         注意:dex2jar需要用最新的,可以直接用于apk。代码增加了zip解压,不再需要手动了,不清楚哪个版本开始的==。才发现的,bat也刚升级了下。
 
2)更多
         看这篇文章就可以了:android反编译小结
 
三、Android反破解
         不废话,参见“看雪学院->Android软件安全->APK反破解技术小结”。
         那位版主现总结了四篇文章,如下:
 
         还有一些回复和摘录,如下:
 
1)可以介绍一下openssl工具,挺好用的。
 
2) 以下为一段整合的回复:
-> 呵呵~!代码混淆能避免被别人破解吗?
-> 不能,只是会增加别人破解的难度。如果要防别人破解的话,最好的方法是使用NDK,用C、C++写的代码,用NDK编成so库,用JNI进行调用!
-> SO库文件包含符号, 调试也比java代码方便, 所以某种意义上说逆向so里面的native code比逆向java还容易。
-> Open Source 成就了 GNU Tool-chain. ELF里面符号表是“一等公民”. 所以默认选项生成的目标文件里面带符号,虽然可以通过选项分离符号,但是很多时候都会忽略了这一点。
不过我相信Open Source模式才是未来软件工程的王道。
 
3)可以多关注dalvik是怎么实现java对JNI调用的。其中会涉及到怎么定位一个native func,有文章可做。
 
4)Dalvik虚拟机类加载机制的SDK类
         A class loader that loads classes from .jar and .apk files containing a classes.dex entry.
         Provides a simple ClassLoader implementation that operates on a list of files and directories in the local file system, but does not attempt to load classes from the network.
 
四、后记
         我用Proguard觉得最大的好处不在于混淆,而在于压缩了代码,apk整整能瘦一圈呢^^
 
五、补充——反编译odex文件
         没关注过ROM,在反编译4.0系统framework.jar定制SDK时,才发现odex这个东西==。
 
         这里也就直接以这举例了^^
 
1. 下载baksmali-1.3.2.jar & smali-1.3.2.jar
2. 模拟器导出整个/system/framework/
         baksmali 反编译是自动找5个核心的BOOTCLASSPATH,当然某些可能会涉及其他的CLASSPATH需要指定-c再添加。
         总之全部弄出来得了,ROM的话也一样吧?不同公司应该会涉及自己的一些包,就这边加吧?
3. 把两个jar放进导出的framework目录
4. 进入framework目录
5. 以下命令进行反编译啦~
java -Xmx512m -jar baksmali-1.3.2.jar -x framework.odex -o out(反编译进out目录)
java -Xmx512M -jar smali-1.3.2.jar -o classes.dex out(重新生成classes.dex)
         第一条命令的话,现版本-a默认为14。出UNEXPECTED TOP-LEVEL EXCEPTION,可能是这出错,记得指定正确。-c,默认会找5个核心CLASSPATH,其他自己指定了。
6. 继而的话,可以用来整成一个apk,或继续dex2jar反编译咯~
 
         参考网址:
                   apk生成odex & 合并odex和少dex的apk为完整apk。
                   当然用这两个jar时,可以先-h看参数说明也差不多。