了解native activity

转自:http://blog.csdn.net/lincyang/article/details/46474319

1.native activity的意义

很多人觉得Android的Fwk提供的支持足够好了,既然Google不推荐用Ndk开发为什么又放宽Ndk的限制而推出可以无Java开发Android App呢?我的理解是不同的技术实现会有其适合的场景。 
Ndk的适用场景官方给出三点:1.平台间的App移植 2.复用现有库 3.对软件性能要求较高的场合比如游戏等。那么native activity在十分适合游戏领域,比如cocos-2dx对其的使用。

2.初步了解native activity

借助SDK提供的NativeActivity类,我们可以创建完全的本地activity而无须编写Java代码。 
需要注意的是,即使是无Java代码编写的应用仍然是跑(运行)在自己的虚拟机中以此与其他应用隔离无不影响。你可以通过JNI的方式调用Fwk层的API,有些像sensor、输入事件等操作可以直接调用本地接口(native interfaces)来完成(linc注:这样才高效嘛)。

有两种方式可以实现native activity。 
1)native_activity.h  
2)android_native_app_glue 
由于第二种方法启用另一个线程处理回调和输入事件,Ndk的例子中就采用了这个实现方式。

3.Ndk自带的例子

这个程序主要演示根据sensor的检测结果在整个屏幕上绘制不同的颜色。 
AndroidManifest.xml 
为了正常使用native activity,我们需要把API级别定在9及以上。

<uses-sdk android:minSdkVersion="9" />
 
 
  • 1

由于我们只使用native code,将android:hasCode设为false。

<application android:label="@string/app_name" android:hasCode="false">
 
 
  • 1

声明NativeActivity类

        <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>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

注意meta-data中的lib_name(native-activity)要与Android.mk中LOCAL_MODULE相同。

Android.mk 
强调模块名称和源文件如下:

LOCAL_MODULE    := native-activity
LOCAL_SRC_FILES := main.c
 
 
  • 1
  • 2

外部库的依赖 
例子中用到了如下几个外部库,log、android(为NDK提供的标准Android支持API)、EGL(图形API)以及OpenGL ES(android用的OpenGL,依赖EGL) 
书写约定为上述库前缀为-l,如下:

LOCAL_LDLIBS    := -llog -landroid -lEGL -lGLESv1_CM
 
 
  • 1

注意: 
实际的库文件名约定为前缀为lib,后缀为.so。比如log库文件名实际为liblog.so。 
这些库的实际位置:

<ndk>/platforms/android-<sdk_version>/arch-<abi>/usr/lib /
 
 
  • 1

比如liblog.so:

$ locate liblog.so
/opt/android-ndk-r10b/platforms/android-12/arch-arm/usr/lib/liblog.so
/opt/android-ndk-r10b/platforms/android-12/arch-mips/usr/lib/liblog.so
/opt/android-ndk-r10b/platforms/android-12/arch-x86/usr/lib/liblog.so
/opt/android-ndk-r10b/platforms/android-13/arch-arm/usr/lib/liblog.so
...
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

静态库 
本例用android_native_app_glue管理NativeActivity生命周期事件:

LOCAL_STATIC_LIBRARIES := android_native_app_glue
 
 
  • 1

我们需要告知编译系统去build这个static library,加上如下语句:

$(call import-module,android/native_app_glue)
 
 
  • 1

源代码 
主要源代码文件只有一个,main.c。 
引入的头文件对应在Android.mk中提到的,如下:

#include <EGL/egl.h>
#include <GLES/gl.h>

#include <android/sensor.h>
#include <android/log.h>
#include <android_native_app_glue>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

程序的入口是android_main,通过android_native_app_glue调入并传入一个预定义state结构来管理NativeActivity的回调。

void android_main(struct android_app* state)
 
 
  • 1

结构android_app的定义参见/sources/android/native_app_glue/android_native_app_glue.h

接下来程序通过glue库来处理事件队列,参考如下代码:

    struct engine engine;

    // Make sure glue isn't stripped.
    app_dummy();

    memset(&engine, 0, sizeof(engine));
    state->userData = &engine;
    state->onAppCmd = engine_handle_cmd;
    state->onInputEvent = engine_handle_input;
    engine.app = state;
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

准备sensor

    // Prepare to monitor accelerometer
    engine.sensorManager = ASensorManager_getInstance();
    engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
            ASENSOR_TYPE_ACCELEROMETER);
    engine.sensorEventQueue = ASensorManager_createEventQueue(engine.sensorManager,
            state->looper, LOOPER_ID_USER, NULL, NULL);
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

处理消息循环

while (1) {
        // Read all pending events.
        int ident;
        int events;
        struct android_poll_source* source;


        // If not animating, we will block forever waiting for events.
        // If animating, we loop until all events are read, then continue
        // to draw the next frame of animation.
        while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, NULL,
&events,
                (void**)&source)) >= 0) {


            // Process this event.
            if (source != NULL) {
                source->process(state, source);
            }


            // If a sensor has data, process it now.
            if (ident == LOOPER_ID_USER) {
                if (engine.accelerometerSensor != NULL) {
                    ASensorEvent event;
                    while (ASensorEventQueue_getEvents(engine.sensorEventQueue,
                            &event, 1) > 0) {
                        LOGI("accelerometer: x=%f y=%f z=%f",
                                event.acceleration.x, event.acceleration.y,
                                event.acceleration.z);
                    }
                }
            }


        // Check if we are exiting.
        if (state->destroyRequested != 0) {
            engine_term_display(&engine);
            return;
        }
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

队列为空时,调用OpenGL绘制屏幕

        if (engine.animating) {
            // Done with events; draw next animation frame.
            engine.state.angle += .01f;
            if (engine.state.angle > 1) {
                engine.state.angle = 0;
            }

            // Drawing is throttled to the screen update rate, so there
            // is no need to do timing here.
            engine_draw_frame(&engine);
        }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

编译 
首先通过NDK编译出so文件,在根目录下直接执行ndk-build即可:

$ ndk-build
[armeabi-v7a] Compile thumb  : native-activity <= main.c
[armeabi-v7a] Compile thumb  : android_native_app_glue <= android_native_app_glue.c
[armeabi-v7a] StaticLibrary  : libandroid_native_app_glue.a
[armeabi-v7a] SharedLibrary  : libnative-activity.so
[armeabi-v7a] Install        : libnative-activity.so => libs/armeabi-v7a/libnative-activity.so
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

上述只摘录出armeabi-v7a一个平台的编译log,由于在Application.mk中没有指明特定平台,编译系统会编译出其他armeabi、x86和mips平台的so。

然后再编译apk 
我尝试将工程向AS中导入,发现没能配置好gradle编译环境,无法编译。 
接着我就借助ant来编译,参考如下步骤:

$ android update project -p .
Updated and renamed default.properties to project.properties
Updated local.properties
No project name specified, using Activity name 'NativeActivity'.
If you wish to change it, edit the first line of build.xml.
Added file ./build.xml
Added file ./proguard-project.txt

$ ant debug
...
[echo] Debug Package: /opt/android-ndk-r10b/samples/native-activity/bin/NativeActivity-debug.apk
...
BUILD SUCCESSFUL
Total time: 3 seconds
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

最后 
安装运行吧!

adb install /opt/android-ndk-r10b/samples/native-activity/bin/NativeActivity-debug.apk
 
 
  • 1

参考: 
http://blog.csdn.net/lincyang/article/details/40950153


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值