2023年6月27日发(作者:)
android截屏代码实现⽅法
最近由于项⽬需要,在学习系统。android是⼀个基于linux的专门针对⼿机平台的操作系统。当然,现在的android 3似乎也将进⼊平板电脑的市场。由于⾄今为⽌,⼤部分的智能⼿机采⽤的是ARM的硬件平台,因此android本⾝对ARM的平台进⾏了全⾯的⽀持,从源代码中可以看出,也在逐步加⼊对x86平台的⽀持,暂时没有看到第三个平台的⾝影。这篇⽂章是我对android系统认识的⼀个总结,同时介绍⼀下我⾄今为⽌发现的获取屏幕图像数据的⽅法。经过⼀定的搜索,我发现⽅法有很多种,⽽实现效果会有所差别。其中,有通过最顶层的Android SDK进⾏截屏,也可以通过C直接读取framebuffer实现。由于framebuffer的⽅法⽹上虽然有很多,但是很多我认为并没有写的⼗分清楚,特别是在编译的⽅法上,没有找到很好的⽂章,可能是因为⾃⼰找的不够,或者android本⾝就在不断发展。对此,我在最后给出了⼀个Android Native Programming的Hello World Howto,需要先到github上mirror下来Android的源代码(2.多G),⾥边将会带所有的编译器和Emulator等⼯具。1 android之我的粗浅理解android的版本号很有意思,⼀个版本号对应⼀个API Level(⽐如android 2.3.3则对应Android API Level 10)。写这篇⽂章的时候,最新的android版本号为3.1,⽽API Level为12。学习android,⾸先需要了解的是其系统框架。如下图所⽰:android操作系统框架图这个图在⽹上⽐⽐皆是,这⾥还是贴了⼀下,因为的确可以⽐较好的描述这个系统。它的最底层是linux的内核,只有这⼀层是⼯作在内核级的,其余三层都是⼯作在⽤户级的。这⾥,android也不是使⽤的标准的linux内核,⽽是⼀个经过了裁剪,并添加了⼀些特定功能的内核。其中⼀个让我记得的⽐较有意思的feature是,android内核中会有⼀个叫做Low Memory Killer的驱动,它的主要功能是在系统缺少内存的情况下,杀死进程。显然,我们平时的电脑中,往往不是很需要这个东西;⽽在⼿机中,由于资源⼗分有限,缺少内存的现象或许会发⽣的⾮常频繁,这个功能似乎就显得⼗分重要了(或许还有⼀个原因是⼿机没有虚拟内存?毕竟它是⽤Flash作为长期存储介质,⽽Flash的特性似乎并不适合作为虚拟内存来使⽤)。我想这是android针对⼿机定制进⾏优化的⼀个很好的例⼦。第⼆层就是所谓的Native层,由C/C++实现。如果熟悉ARM的应⽤程序开发的话,我理解这⼀层就是ARM平台的应⽤开发层。我们仍然可以⽤⼀个类似arm-linux-gcc的交叉编译⼯具对C程序进⾏编译(这⾥是arm-linux-androideabi-gcc)进⾏编译,具体的⽅法⼀会详细介绍。⽽在这⼀层,系统给我们提供的库可是⽐较少的,往往就是最基本的libc等(从提供的可⽤C基础库来看,数量上肯定是android
import tputStream;import DateFormat;import ;import ;
import ty;import ;import ;import ;import kListener;import ;
public class HelloAndroid extends Activity {
private Button button;
/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState); this .setContentView(); this .button = (Button) this .findViewById(_button); this .lickListener( new OnClickListener() {
public void onClick(View v) { SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd_HH-mm-ss" , ); String fname = "/sdcard/" + ( new Date()) + ".png" ; View view = tView(); wingCacheEnabled( true ); rawingCache(); Bitmap bitmap = wingCache(); if (bitmap != null ) { n( "bitmap got!" ); try { FileOutputStream out = new FileOutputStream(fname); ss(, 100 , out); n( "file " + fname + "output done." ); } catch (Exception e) { tackTrace(); } } else { n( "bitmap is NULL!" ); } }
});
}}这个代码会在按下app中按键的时候⾃动在⼿机的/sdcard/⽬录下⽣成⼀个时间戳命名的png截屏⽂件。这种截屏有⼀个问题,就是只能截到⼀部分,⽐如电池指⽰部分就截不出来了。3.2 基于Android ddmlib进⾏截屏这种⽅法。我也没有测试过,此处略过。3.3 Android本地编程(Native Programming)读取framebuffer这是我现在使⽤的⽅法。它的优点是整个屏幕都可以截下来,同时不需要写JNI,也不需要Java层的实现。⽽且如果是emulator的话,也可以直接⽤adb来操作,⼗分⽅便(其实,有⼀个库应该实现了类似的功能,但是我尝试了⼀下没有截图成功,图⽚⼤⼩不正确,且是⿊屏。就没有进⼀步尝试了)。3.3.1 Android的framebuffer介绍framebuffer是linux内核对显⽰的最底层驱动。在⼀般的linux⽂件系统中,通过/dev/fb0设备⽂件来提供给应⽤程序对framebuffer进⾏读写的访问。这⾥,如果有多个显⽰设备,就将依次出现fb1,fb2,…等⽂件。⽽在我们所说的android系统中,这个设备⽂件被放在了/dev/graphics/fb0,⽽且往往只有这⼀个。3.3.2 framebuffer的读取读取的⽅法很简单,就将/dev/graphics/fb0当作⼀般的⽂件读取即可。可以通过ioctl()⽅法获取图像的长宽,以及每⼀个pixel对应的数据量。在android系统中,采⽤的是的编码⽅式。这⾥编程的⽅法是C最基本的,难点主要是编译器的配置。我会在第4节介绍⼀个Native的tutorial: hello world程序,这⾥会讲到编译的⽅法和具体配置。3.3.3 在android emulator中利⽤命令直接进⾏截屏有⼀个⼤致的流程。主要是⽤cat读取fb,后⽤ffmpeg转换编码的⽅法。此处略。4 Android本地编程⼊门:”hello world!” again!我简单介绍⼀下怎么在android上开发基本的C程序。如果做过ARM的C应⽤程序开发的话会发现,ARM⼀般情况下提供了⼗分完备的编译器,⽽android没有⽽已(android提供了完善的Java层开发⼯具,C的却不是那么完善)。4.1 编写hello.c这个太简单了,不是么?#include
### these two things have to be set firstANDROID_VER=android-8ANDROID_ROOT=/home/xzpeter/android
PLATFORM_DIR=${ANDROID_ROOT}/prebuilt/ndk/android-ndk-r4/platformsSYSROOT=${PLATFORM_DIR}/${ANDROID_VER}/arch-arm
EABI_GCC=${ANDROID_ROOT}/prebuilt/linux-x86/toolchain/arm-linux-androideabi-4.4.x/bin/arm-linux-androideabi-gcc
CC=${EABI_GCC} --sysroot=${SYSROOT}这⾥,ANDROID_ROOT和ANDROID_VER是需要针对⾃⼰的android source⽬录地址和android API level修改⼀下的。这⾥的androidsource是我⽤repo sync从github上mirror下来的android源代码。4.3 编写Makefile利⽤上⾯的make_android,写Makefile:# to make x86 version of code, run: "make X86=1"ifdef X86CC=gccCLFAGS=-gelseinclude make_androidendif
default: hello
hello: hello.o
clean: rm hello *.o我们提供了X86和android两种编译⽅式,默认是android⽅式。4.4 编译可以⽤make X86=1先在本地编译⼀下,并运⾏./hello试试看。如果想编译android版本,先make clean⼀下,然后直接make就可以了。4.5 在模拟器中运⾏利⽤shell命令启动emulator并将⽂件放到⽬标模拟器上去:emulator - avd my_avd # my_avd is my config name of avd# wait for some time to boot upadb push . / hello / data / helloadb shell chmod 0755 / data / helloadb shell . / data / hello应该可以看到返回的”hello world!”字符串了。转载地址为:
发布者:admin,转转请注明出处:http://www.yc00.com/xiaochengxu/1687841736a49965.html
评论列表(0条)