OpenGL 编程/安装/Android NDK
我们的 GLUT 教程可以使用提供的简单包装器在 Android 上运行。
注意:包装器将集成到下一个官方 FreeGLUT(版本 3.0)中!
要了解 GLUT 包装器在内部的工作原理,请参阅 Android GLUT 包装器。
首先,您需要一个最小的 Java 开发环境
sudo apt-get install openjdk-7-jdk ant
然后从 Android 开发者 获取 Android NDK r9d,以编译用于 Android 的 C/C++ 代码。
最后,您需要安装 Android API 级别 10,从同一网站获取 Android SDK 并使用android图形工具来安装它。
程序本身可能还需要 GLM 和 FreeType 库 - 请参阅下面的专用部分。
Android 模拟器从 2012 年 4 月开始仅支持 OpenGL ES 2.0,需要特定的模拟器配置和系统映像,并且似乎并非在所有平台上都能正常工作。
还要注意,“API 演示”应用程序提供了一个“OpenGL ES 2.0”示例,如果 2.0 不可用,它会静默且令人困惑地回退到 OpenGL ES 1.0,因此这不是一个很好的测试来查看是否支持 OpenGL ES 2.0。
在 Android 上使用 支持设备 实验 OpenGL 2.0 仍然是最好的选择。
官方文档:https://developer.android.com.cn/tools/devices/emulator.html#accel-graphics
当您通过 USB 连接设备时,可以使用 adb
命令(来自 Android SDK)浏览文件系统、安装应用程序、调试它们等。
$ adb devices List of devices attached 4520412B47C0207D device
在本维基教科书中,示例基于 GLUT 库。
由于 GLUT 尚未移植到 Android,因此我们为 Android 编写了一个简单的 GLUT 兼容包装器(请参阅 代码库)。
注意:包装器仍处于早期阶段,可能会在不久的将来发生变化。
查看“android_wrapper/”目录。
- 通过 USB 插入您的设备(智能手机、平板电脑...)。
- 将 Android 工具添加到您的 PATH,例如
export PATH="$PATH:/usr/src/android-sdk-linux/tools:/usr/src/android-sdk-linux/platform-tools:/usr/src/android-ndk-r9d"
- 在
jni/
目录中,使src
成为您需要编译的 GLUT 代码的符号链接(例如ln -nfs ../../tut02_clean src
)。 - 使
assets
成为您正在编译的教程的符号链接(例如ln -s jni/src assets
)。 - 现在您可以键入
make clean; make && make install
- 您将在设备上获得一个“OpenGL 维基教科书”应用程序,可以立即运行!
要使您的应用程序全屏,请在您的 AndroidManifest.xml 中添加此属性
<application
...
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
>
默认的 Android 键盘没有 F1/F2/F3 等键。
相反,您可以使用 Hacker's Keyboard,这是一种具有更多键的替代输入法
确保您的应用程序在 AndroidManifest.xml
中定义了 android:icon
。
<application ...
android:icon="@drawable/icon"
创建两个图标
- res/drawable/icon.png (48x48)
- res/drawable-hdpi/icon.png (72x72)
现在您的应用程序将在启动器上有一个自定义图标。
如果您想查看程序的标准输出(stdout 和 stderr),您需要将它们重定向到系统日志
adb shell root
adb shell stop
adb shell setprop log.redirect-stdio true
adb shell start # this may restart your Android session
要检查日志文件,您可以使用
- 命令:adb logcat
ddms
实用程序,它具有图形 GUI 来浏览日志- Eclipse,它嵌入了一个类似于 DDMS 的 LogCat 查看器
以下操作将在从 C/C++ 调用 JNI 时开启更多检查
adb shell stop
adb shell setprop dalvik.vm.checkjni true
adb shell start
您将在系统日志中获得额外的跟踪信息,并且 JNI 对其接受的内容将更加严格。
GDB 也可以启用。
注意:在 NDKr7 中,在 Android.mk 中使用“stabs”格式进行调试符号,否则 GDB 将显示错误的源代码行 [1]
LOCAL_CXXFLAGS := -gstabs+
GDB 需要调试版本,在构建 C++ 代码时添加 NDK_DEBUG=1
ndk-build NDK_DEBUG=1
在启动 gdb 时,确保您的 AndroidManifest.xml 提到了它是可调试的,否则 gdb 的行为会很糟糕(缺乏线程信息、崩溃等)
<application ...
android:hasCode="true" android:debuggable="true"
gdb-server 需要几秒钟才能在设备上启动,因此您的程序将在它被调试器暂停之前开始运行。一个解决方法是在您的 android_main
函数中添加一个等待
sleep(5);
要启动调试会话,请键入
ndk-gdb --start
如果您遇到以下错误:
E/AndroidRuntime( 3021): java.lang.RuntimeException: Unable to start activity ComponentInfo{org.wikibooks.OpenGL/android.app.NativeActivity}: java.lang.IllegalArgumentException: Unable to load native library: /data/data/org.wikibook.OpenGL/lib/libnative-activity.so
系统无法加载您的 .so 文件,原因是底层问题。
要获取更多信息,您需要创建一个手动加载库的最小 Java 应用程序
- src/com/example/test_native_activity/Main.java
package com.example.test_native_activity;
import android.app.Activity;
import android.os.Bundle;
public class Main extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
System.loadLibrary("native-activity");
}
}
- AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.test_native_activity"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7" />
<application android:label="test_native_activity">
<activity android:name=".Main">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
编译、安装并准备它
android update project --name test_native_activity --path . --target "android-10"
ant debug
ant installd
adb shell
su -c bash
cd /data/data/
cp -a org.wikibooks.OpenGL/lib/libnative-activity.so com.example.test_native_activity/lib/
运行此应用程序时,您将在 Android 日志中获得更精确的错误,例如错误的 STL 实现
E/AndroidRuntime(3009): java.lang.UnsatisfiedLinkError: Cannot load library: reloc_library[1311]: 2323 cannot locate '_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc'...
或缺少依赖项
E/AndroidRuntime( 3327): java.lang.UnsatisfiedLinkError: Cannot load library:link_image[1962]: 2323 could not load needed library 'libglut.so.3' for 'libnative-activity.so' (load_library[1104]: Library 'libglut.so.3' not found)
在最糟糕的情况下,库甚至可能无法正确加载。例如,当全局静态变量的 C++ 构造函数在库加载时崩溃时,即使在应用程序启动之前也会发生这种情况。您需要在 C 级重新生成库加载
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char* argv[]) {
const char* err = NULL;
const char* filename = "/data/data/org.wikibooks.OpenGL/lib/libnative-activity.so";
if (argc == 2)
filename = argv[1];
printf("Clearing errors: "); fflush(stdout);
err = dlerror();
printf("%s\n", (err == NULL) ? "OK" : err); fflush(stdout);
printf("Loading library: "); fflush(stdout);
void* handle = dlopen(filename, RTLD_LAZY);
err = dlerror();
printf("%s\n", (err == NULL) ? "OK" : err); fflush(stdout);
if (handle != NULL) {
printf("Loading symbol: "); fflush(stdout);
dlsym(handle, "ANativeActivity_onCreate");
err = dlerror();
printf("%s\n", (err == NULL) ? "OK" : err); fflush(stdout);
}
}
然后将其发送到设备并执行它
$ arm-linux-androideabi-gcc test-dlsym.c
$ adb push a.out /
$ adb shell
# /a.out
Clearing errors: OK
Loading library: OK
Loading symbol: OK
您也可以使用 strace
获取更多精度
# strace /a.out
默认情况下,Android 没有 ldd
,但您可以使用以下方法模拟它:
arm-linux-androideabi-objdump -x libs/armeabi/libnative-activity.so | grep NEEDED
# or
arm-linux-androideabi-readelf -d libs/armeabi/libnative-activity.so | grep NEEDED
当您只使用 GLES2 函数时,您的应用程序几乎可以移植到台式机和移动设备。还有一些问题需要解决
- GLSL 的
#version
不同 - GLES2 需要与 OpenGL 2.1 不兼容的精度提示。
有关详细信息和建议的解决方案,请参阅基本教程 02 和 03。
要安装 GLM,您只需要将最新版本解压缩到 jni/glm
中(这样 jni/glm/glm.hpp
就存在)。它是一个仅包含头文件的库,不需要单独编译。
- 从 http://lonesock.net/soil.html 下载 Simple OpenGL Image Library
- 应用来自android_wrapper/soil.patch.
- 的补丁按照.
- projects/Android/Makefile中的说明进行操作.
NDK 模块已准备好在
src/build/soil/FreeType
/usr/src/android-ndk-r8c/build/tools/make-standalone-toolchain.sh \
--platform=android-14 --install-dir=/usr/src/ndk-standalone-14-arm --arch=arm
NDK_STANDALONE=/usr/src/ndk-standalone-14-arm
PATH=$NDK_STANDALONE/bin:$PATH
如果您需要 FreeType(一个渲染字体的库),您需要交叉编译它。注意:Android 系统使用 FreeType,但内部它不将其公开给原生应用程序。
tar xf freetype-2.6.tar.bz2
cd freetype-2.6/
# For simplicity, use bundled zlib, and avoid harfbuzz cyclic dependency
./configure --host=arm-linux-androideabi --prefix=/freetype --without-zlib --with-png=no --with-harfbuzz=no
make -j$(nproc)
make install DESTDIR=$(pwd)
首先,从 NDK 准备交叉编译器
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := freetype
LOCAL_SRC_FILES := lib/libfreetype.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/include/freetype2
include $(PREBUILT_STATIC_LIBRARY)
然后使用它交叉编译 freetype
然后在新的 freetype/
目录中编写一个 Android.mk
文件
有关详细信息,请参阅 NDK 中的 docs/STANDALONE-TOOLCHAIN.html
和 docs/PREBUILTS.html
。CLEAR_VARS
部分没有记录,但对于避免路径混淆是必要的;它用于 native_app_glue
NDK 模块。
LOCAL_STATIC_LIBRARIES := freetype
(或者,如果您不打算使用 NDK 构建系统,则可以在 --prefix=/usr/src/ndk-standalone-14-arm/sysroot/usr 中安装它。)
要在您的项目中使用 FreeType,请编辑您的Android.mk
设备标记为脱机
[编辑 | 编辑源代码]您第一次将设备连接到新计算机时,它会要求您确认计算机指纹。在您接受设备屏幕上的确认之前,它会被标记为脱机。如果您没有被要求确认,请确保您的
adb
是最新的。允许非 root 用户访问 USB[编辑 | 编辑源代码]如今,Android 设备在您的
/lib/udev/rules.d/
- 中被引用,非特权用户现在可以安全地连接到设备。
- 如果 adb 在您的新设备上遇到权限问题查看以 root 身份运行
adb
时是否有效(以检查是否为权限问题,或者其他问题)。安装android-tools-adb. - 软件包,其中包含
/lib/udev/rules.d/70-android-tools-adb.rules
usb 2-1: New USB device found, idVendor=18d1, idProduct=4e22
如果不起作用,请手动创建一个 udev 规则,如下所示。
# Galaxy S SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", MODE="0666", GROUP="plugdev"
首先,通过在插入设备后键入“dmesg”来确定设备的 idVendor
;检查是否有
然后创建一个如下所示的 udev 规则,例如在 /etc/udev/rules.d/51-android.rules 中
/etc/init.d/udev restart
(这可以通过 idProduct 进一步细化。)
# ll /dev/bus/usb/002/ total 0 crw-rw-r-T 1 root plugdev 189, 140 janv. 19 21:50 013
然后重新启动 udev 守护进程
如果您插入设备,USB 字符设备应该有“plugdev”组- 参考资料
- 在此页面上评论