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应用来调用。

Android 1.6增加了对于OpenGL ES 1.x的支持
Android 2.0开始支持OpenGL ES 2.0

第二个里程碑 - 支持本地应用开发 (Android 2.3)

Android 2.3是一个重要的版本,这一版本增加了完全用C++写本地应用的接口。

我们看看这一版提供了什么API头文件:

  • native_activity.h
  • looper.h
  • input.h
  • keycodes.h
  • sensor.h
  • rect.h
  • window.h
  • native_window.h
  • native_window_jni.h
  • configuration.h
  • asset_manager.h
  • storage_manager.h
  • obb.h

直至今天,Android 7.0,API level 24的时代,上面这些仍然构成了我们这系列教程的主要内容。

同时,Android 2.3还开始支持EGL接口。

Android 4.0开始支持OpenMAX AL库。

Android 4.3开始支持Open GL ES 3.0版

Android 6.0开始支持trace库

Android 7.0开始支持Vulkan, Camera, Choreographer和Multinework库,同时对Open GL ES 3.2的支持

本地应用和窗口

本地应用的框架

首先,写native应用需要一个本地应用的框架的支持。
Java应用需要写一个manifest.xml,我们也入乡随俗需要写一个,我们先看一个NDK sample的例子:

<?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 .apk has no Java code itself, so set hasCode to false. -->
  <application
      android:allowBackup="false"
      android:fullBackupContent="false"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:hasCode="false">

    <!-- 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 our .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>

因为我们没有写Java代码,所以需要将android:hasCode值设为false.

可以使用NDK中的android_native_app_glue定义的类来对本地API进行封装,我们来看一下,先认识一下后面我们会介绍的几个类:

struct android_app {
    // The application can place a pointer to its own state object
    // here if it likes.
    void* userData;

    // Fill this in with the function to process main app commands (APP_CMD_*)
    void (*onAppCmd)(struct android_app* app, int32_t cmd);

    // Fill this in with the function to process input events.  At this point
    // the event has already been pre-dispatched, and it will be finished upon
    // return.  Return 1 if you have handled the event, 0 for any default
    // dispatching.
    int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event);

    // The ANativeActivity object instance that this app is running in.
    ANativeActivity* activity;

    // The current configuration the app is running in.
    AConfiguration* config;

    // This is the last instance's saved state, as provided at creation time.
    // It is NULL if there was no state.  You can use this as you need; the
    // memory will remain around until you call android_app_exec_cmd() for
    // APP_CMD_RESUME, at which point it will be freed and savedState set to NULL.
    // These variables should only be changed when processing a APP_CMD_SAVE_STATE,
    // at which point they will be initialized to NULL and you can malloc your
    // state and place the information here.  In that case the memory will be
    // freed for you later.
    void* savedState;
    size_t savedStateSize;

    // The ALooper associated with the app's thread.
    ALooper* looper;

    // When non-NULL, this is the input queue from which the app will
    // receive user input events.
    AInputQueue* inputQueue;

    // When non-NULL, this is the window surface that the app can draw in.
    ANativeWindow* window;

    // Current content rectangle of the window; this is the area where the
    // window's content should be placed to be seen by the user.
    ARect contentRect;

    // Current state of the app's activity.  May be either APP_CMD_START,
    // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below.
    int activityState;

    // This is non-zero when the application's NativeActivity is being
    // destroyed and waiting for the app thread to complete.
    int destroyRequested;

    // -------------------------------------------------
    // Below are "private" implementation of the glue code.

    pthread_mutex_t mutex;
    pthread_cond_t cond;

    int msgread;
    int msgwrite;

    pthread_t thread;

    struct android_poll_source cmdPollSource;
    struct android_poll_source inputPollSource;

    int running;
    int stateSaved;
    int destroyed;
    int redrawNeeded;
    AInputQueue* pendingInputQueue;
    ANativeWindow* pendingWindow;
    ARect pendingContentRect;
};

我们看下这个结构中都用到了什么:

  • ANativeActivity: 它是本地应用中对应于android.app.NativeActivity的代理类,定义于android/native_activity.h
  • AConfiguration: 处理配置项。定义于android/configuration.h
  • ALooper: 对应于Java中的Looper,用于处理消息队列,每个线程只能有一个. 定义于android/looper.h
  • AInputQueue: 输入事件的队列,定义于android/input.h中
  • ANativeWindow: 处理窗口的类,定义于android/native_window.h中
  • ARect:代表一个矩形,定义于android/rect.h中

武器库鸟瞰

native应用比起Java应用来,跟Android版本的相关性更高一些。
所以,这些API都是根据平台版本号分成不同的目录的。
下面介绍的android下面的API,对应于Android源码中的frameworks/native/include/中。
在NDK中,以r13b为例,Android 7.0,也就是API 24的头文件位于:android-ndk/r13b/platforms/android-24/arch-arm64/usr/include/中。
我们首先通过一张图来看看Android为我们提供了哪些API:

Paste_Image.png

本地应用和本地窗口类

主要包括下面的头文件:

  • android/native_activity.h
    • ANativeActivity结构:对应android.app.NativeActivity
    • ANativeActivityCallback结构,处理回调
  • android/native_window.h
    • ANativeWindow结构
    • ANativeWindow_Buffer结构
  • android/rect.h
    • ARect结构:有left, top, right, bottom四个属性的矩阵的抽象
  • android/native_window_jni.h: 辅助类
  • android/window.h: 辅助类

资源管理类

  • android/asset_manager.h
    • AAssetManager结构
    • AAssetDir结构
    • AAsset结构
  • android/asset_manager_jni.h
    • AAssetManager_fromJava结构

位图类

  • bitmap.h
    • AndroidBitmapInfo结构

配置类

  • configuration.h
    • AConfiguration结构

输入类

  • input.h
    • AInputEvent结构
    • AInputQueue结构
  • keycodes.h:定义了键码的enum

Looper类

  • android/looper.h
    • ALooper结构
    • ALooper_callbackFunc结构

存储类

  • android/storage_manager.h
    • AStorageManager结构
    • AStorageManager_obbCallbackFunc结构
  • android/obb.h
    • AObbInfo结构

传感器类

  • android/sensor.h
    • ASensorVector结构
    • AMetaDataEvent结构
    • AUncalibratedEvent结构
    • AHeartRateEvent结构
    • ADynamicSensorEvent结构
    • AAdditionalInfoEvent结构
    • ASensorEvent结构
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,392评论 25 707
  • afinalAfinal是一个android的ioc,orm框架 https://github.com/yangf...
    passiontim阅读 15,396评论 2 45
  • 是否有那么个地方,不悲不喜,几经岁月的洗礼。你突兀地望见了这里,从此有了这万般的情绪,这儿不一定古庙长街,不一...
    渝喃笙阅读 253评论 2 1
  • 夜已深,白天车来车往、人声鼎沸的街道此时却显得颇为冷清,只有路边昏黄的路灯仍在坚守着自己日复一日的工作,或许是因为...
    夏若溪语阅读 736评论 4 1
  • 生活就是一个以你所在地为战场的风起云涌的战争。 我们都在努力的为自己的衣食住行而奋战,为自己美好的将来...
    我只要你不要他i阅读 233评论 0 0