Android native应用开发简明教程 (2) - 本地应用的原理

本地应用原理

从NativeActivity说起

本地App,本质上是一个Java App调用了一个JNI的库,而应用的逻辑通过native代码来实现。
NativeActivity是继承自Activity的一个类,代码在:/frameworks/base/core/java/android/app/NativeActivity.java中:

public class NativeActivity extends Activity implements SurfaceHolder.Callback2,InputQueue.Callback, OnGlobalLayoutListener{
...

然后我们再看NativeActivity的onCreate方法:

     @Override
     protected void onCreate(Bundle savedInstanceState) {
         String libname = "main";
         String funcname = "ANativeActivity_onCreate";
         ActivityInfo ai;
...

这里我们就看到了一个重要的函数:ANativeActivity_onCreate,这个函数将是本地应用的入口函数。

...
         try {
             ai = getPackageManager().getActivityInfo(
                     getIntent().getComponent(), PackageManager.GET_META_DATA);
             if (ai.metaData != null) {
                 String ln = ai.metaData.getString(META_DATA_LIB_NAME);
                 if (ln != null) libname = ln;
                 ln = ai.metaData.getString(META_DATA_FUNC_NAME);
                 if (ln != null) funcname = ln;
             }
         } catch (PackageManager.NameNotFoundException e) {
             throw new RuntimeException("Error getting activity info", e);
         }

         BaseDexClassLoader classLoader = (BaseDexClassLoader) getClassLoader();
         String path = classLoader.findLibrary(libname);
...

大家还记得上一讲我们贴的AndroidManifest.xml吗?记得这一行meta data吗:

      <!-- Tell NativeActivity the name of our .so -->
      <meta-data android:name="android.app.lib_name"
                 android:value="native-activity" />

我们的本地应用生成的so库的名字,就是通过这里来读出来的。

最后,通用本地代码的入口在这里:

         mNativeHandle = loadNativeCode(path, funcname, Looper.myQueue(),
                 getAbsolutePath(getFilesDir()), getAbsolutePath(getObbDir()),
                 getAbsolutePath(getExternalFilesDir(null)),
                 Build.VERSION.SDK_INT, getAssets(), nativeSavedState,
                 classLoader, classLoader.getLdLibraryPath());

入口点函数是funcname,大家还记得它的定义吧:

String funcname = "ANativeActivity_onCreate";
...
                 ln = ai.metaData.getString(META_DATA_FUNC_NAME);
                 if (ln != null) funcname = ln;

默认情况下,这个入口函数就是ANativeActivity_onCreate.

JNI层的实现

我们继续跟进去看jni中对于loadNativeCode_native的调用:

 loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jstring funcName,
         jobject messageQueue, jstring internalDataDir, jstring obbDir,
         jstring externalDataDir, jint sdkVersion, jobject jAssetMgr,
         jbyteArray savedState, jobject classLoader, jstring libraryPath) {
...

下面,根据funcName,就是默认是ANativeActivity_onCreate的这个函数,将变成函数指针,类型为ANativeActivity_createFunc

...
         void* funcPtr = NULL;
         const char* funcStr = env->GetStringUTFChars(funcName, NULL);
         if (needNativeBridge) {
             funcPtr = NativeBridgeGetTrampoline(handle, funcStr, NULL, 0);
         } else {
             funcPtr = dlsym(handle, funcStr);
         }
         code.reset(new NativeCode(handle, (ANativeActivity_createFunc*)funcPtr));
         env->ReleaseStringUTFChars(funcName, funcStr);

         if (code->createActivityFunc == NULL) {
             ALOGW("ANativeActivity_onCreate not found");
             return 0;
         }
...

android_native_app_glue的实现

我们再来看看NDK中的android_native_app_glue中,入口函数ANativeActivity_onCreate都做了些什么:

void ANativeActivity_onCreate(ANativeActivity* activity,
        void* savedState, size_t savedStateSize) {
    LOGV("Creating: %p\n", activity);
    activity->callbacks->onDestroy = onDestroy;
    activity->callbacks->onStart = onStart;
    activity->callbacks->onResume = onResume;
    activity->callbacks->onSaveInstanceState = onSaveInstanceState;
    activity->callbacks->onPause = onPause;
    activity->callbacks->onStop = onStop;
    activity->callbacks->onConfigurationChanged = onConfigurationChanged;
    activity->callbacks->onLowMemory = onLowMemory;
    activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
    activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
    activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
    activity->callbacks->onInputQueueCreated = onInputQueueCreated;
    activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;

    activity->instance = android_app_create(activity, savedState, savedStateSize);
}

可以看到,这个封装中,除了设置了若干个callback函数以外,就是封装成了android_app_create函数。

我们再来看android_app_create的实现:

static struct android_app android_app_create(ANativeActivity activity,
        void* savedState, size_t savedStateSize) {
    struct android_app android_app = (struct android_app)malloc(sizeof(struct android_app));
    memset(android_app, 0, sizeof(struct android_app));
    android_app->activity = activity;

    pthread_mutex_init(&android_app->mutex, NULL);
    pthread_cond_init(&android_app->cond, NULL);

    if (savedState != NULL) {
        android_app->savedState = malloc(savedStateSize);
        android_app->savedStateSize = savedStateSize;
        memcpy(android_app->savedState, savedState, savedStateSize);
    }

    int msgpipe[2];
    if (pipe(msgpipe)) {
        LOGE("could not create pipe: %s", strerror(errno));
        return NULL;
    }
    android_app->msgread = msgpipe[0];
    android_app->msgwrite = msgpipe[1];

    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    pthread_create(&android_app->thread, &attr, android_app_entry, android_app);

    // Wait for thread to start.
    pthread_mutex_lock(&android_app->mutex);
    while (!android_app->running) {
        pthread_cond_wait(&android_app->cond, &android_app->mutex);
    }
    pthread_mutex_unlock(&android_app->mutex);

    return android_app;
}

这个封装处理了线程安全相关的问题,创新主线程来执行android_app_entry函数。

static void android_app_entry(void param) {
    struct android_app android_app = (struct android_app)param;

    android_app->config = AConfiguration_new();
    AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);

    print_cur_config(android_app);

    android_app->cmdPollSource.id = LOOPER_ID_MAIN;
    android_app->cmdPollSource.app = android_app;
    android_app->cmdPollSource.process = process_cmd;
    android_app->inputPollSource.id = LOOPER_ID_INPUT;
    android_app->inputPollSource.app = android_app;
    android_app->inputPollSource.process = process_input;

    ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
    ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
            &android_app->cmdPollSource);
    android_app->looper = looper;

    pthread_mutex_lock(&android_app->mutex);
    android_app->running = 1;
    pthread_cond_broadcast(&android_app->cond);
    pthread_mutex_unlock(&android_app->mutex);

    android_main(android_app);

    android_app_destroy(android_app);
    return NULL;
}

这一层的封装,将处理AConfiguration。但是最主要的是要处理ALooper,构建一个消息队列。
最终才会调用android_main,这一层才是android_native_app_glue封装好的对外接口。

小结

  • Android支持通过本质上是个so的本地代码来写应用
  • 骨架代码是Android framework中的NativeActivity,该类通过装载so库的方式来调用本地应用代码
  • 默认的入口点在ANativeActivity_onCreate,函数名和库名都可以在AndroidManifest.xml中配置

最后,我们来看一张图来复习一下:

时间: 2024-09-08 11:37:18

Android native应用开发简明教程 (2) - 本地应用的原理的相关文章

Android native应用开发简明教程 (1) - 本地开发武器库概览

Android本地开发武器库概览 Android本地开发支持简史 Android 1.0的时代,没有提供对于C/C++开发本地Android代码的支持,尽管Android系统本身使用了大量的C++做底层开发. 第一个里程碑 - 支持jni开发so库 (Android 1.5) Android第一次支持本地开发是在Android 1.5版本,对应Android API level 3.这一版本,有了正式的Android NDK的支持,可以通过jni写so库的方式,供Android应用来调用. An

Android平台Qt开发入门教程

     很多人会问,Android平台可以不使用Java开发应用程序??      我做Android平台native开发之前,也有这么想过,但是我又想,底层系统全是c/c++代码,用c/c++开发Android平台程序是可能的,只是需要使用系统非公开的API(就是android源代码,而非NDK里面提供的头文件),比如libui和skia.       好了,由于我的工作是把C++中间件移植到Android平台,所以会对Qt for android这个项目比较了解,毕竟国内做这些的还比较少,

php版微信公众账号第三方管理工具开发简明教程_php实例

本文讲述了php版微信公众账号第三方管理工具开发方法.分享给大家供大家参考,具体如下: 最近在捣鼓微信公共平台提供的API,等确实一个获取用户信息的API. 所以没有办法,只能自己去获取,手动填写当然可以解决问题,当然编程不就是为了让生活变的更简单么? 当然,远程抓取微信公共平台数据的想法就油然而生,当然第一个想到了CURL. CURL可以远程提交表达,我感觉微信是提议让我们怎么的,只要不是恶意刷接口,就不会出现验证码. 主要注意的几个问题: ① 远程登录接口是时候的HTTPS协议. ② 登录成

php版银联支付接口开发简明教程_php技巧

本文实例讲述了php版银联支付接口开发的方法.分享给大家供大家参考,具体如下: 支付接口现在有第三方的支付接口也有银行的支付接口.这里就来介绍php版本银联支付接口开发的方法. 银联支付,首先要注意二重要的部分: PHP运行环境是5.4.18以上 开了扩展openssl 开发手册上面的列子只做参考,因为基本都是错的.你可以试着去官网下一个demo...注意现在银联开发,没有测试密钥提供,只能在正式环境开发 下面是我用ThinkPHP编写的一个支付类 /** * 银联支付 v0.1 * @auth

php版微信公众账号第三方管理工具开发简明教程

本文讲述了php版微信公众账号第三方管理工具开发方法.分享给大家供大家参考,具体如下: 最近在捣鼓微信公共平台提供的API,等确实一个获取用户信息的API. 所以没有办法,只能自己去获取,手动填写当然可以解决问题,当然编程不就是为了让生活变的更简单么? 当然,远程抓取微信公共平台数据的想法就油然而生,当然第一个想到了CURL. CURL可以远程提交表达,我感觉微信是提议让我们怎么的,只要不是恶意刷接口,就不会出现验证码. 主要注意的几个问题: ① 远程登录接口是时候的HTTPS协议. ② 登录成

Android Studio的JNI开发快餐教程

Android Studio的JNI开发快餐教程 从eclipse换到Android Studio之后,原来的NDK集成已经不能用了.同时,AndroidStudio也是在快速迭代进步中,不仅支持内置的ndk支持插件,还有支持外部编译系统的plugin. 而且这还是在实验中的结果,在不久的将来,还可能有更新的变化.不过,万变不离其宗,我们打好基础,形式上的东西跟着Android Studio变就好. 旧式的NDK支持 首先说明,既然是Android Studio认为它已经过时了,所以我们需要在g

一看就懂的Android APP开发入门教程

  这篇文章主要介绍了Android APP开发入门教程,从SDK下载.开发环境搭建.代码编写.APP打包等步骤一一讲解,非常简明的一个Android APP开发入门教程,需要的朋友可以参考下 工作中有做过手机App项目,前端和android或ios程序员配合完成整个项目的开发,开发过程中与ios程序配合基本没什么问题,而android各种机子和rom的问题很多,这也让我产生了学习android和ios程序开发的兴趣.于是凌晨一点睡不着写了第一个android程序HelloAndroid,po出

Android编程Widget创建与使用方法简明教程_Android

本文实例讲述了Android编程Widget创建与使用方法.分享给大家供大家参考,具体如下: Android reference中有关于如何建立一个Widget的详细方法,这里简要说明一下,详情可以查看Android SDK中自带的reference. 要建立一个Widget,分为如下几个步骤: (1) 创建一个类,让其继承类AppWidgetProvider,在AppWidgetProvider中有许多方法,例如onDelete(Context,int[]),onEnable(Context)

Android OpenGL ES 开发教程 从入门到精通

From:http://blog.csdn.net/mapdigit/article/details/7526556 Android OpenGL ES 简明开发教程 Android OpenGL ES 简明开发教程一:概述 Android OpenGL ES 简明开发教程二:构造OpenGL ES View Android OpenGL ES 简明开发教程三:3D绘图基本概念 Android OpenGL ES 简明开发教程四:3D 坐标变换 Android OpenGL ES 简明开发教程五