[置顶] Android 应用内禁止截屏功能的实现
2017-05-23 13:57
1506 查看
截图介绍
截图的原理
DDMS的实现方式
DDMS是通过adb调用设备端的adbd(ADBdaemon)提供的framebufferservice进行截屏(源码在system/core/adb/framebuffer_service.c),在较早版本的Android中,framebufferservice通过直接读framebuffer设备(/dev/graphics/fb0)来截屏,但是读framebuffer设备(/dev/graphics/fb0)的方式在某些使用硬件overlay显示的设备上可能无法截取到某些画面(例如videoplayback和camerapreview画面)。在较新版本的Android中,framebufferservice则调用截屏工具screencap来截屏。
screencap工具
screencap是Android原生自带的工具,是一个C写的可执行文件,在设备上的/system/bin/下面可以找到它,screencap截屏后可保存为PNG格式文件或RGBRAW文件。screencap的源码frameworks/base/cmds/screencap/,它调用SurfaceFlinger提供的截屏接口ScreenshotClient,其源码在
frameworks/native/libs/gui/SurfaceComposerClient.cpp(该路径在不同版本的Android源码中可能略有差别),ScreenshotClient通过进程间通信调用SurfaceFlingerservice的截屏功能,源码在
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp中的函数
SurfaceFlinger::captureScreen。
SurfaceFlinger提供的上述截屏接口则可以完美截取任何屏幕画面,因此相对来说是Android上最正规最完善的截屏方法,使用起来也非常简单。
关于SurfaceFlinger和framebuffer的内容不再做赘述,因为描述起来非常复杂,不是本文的重点,有兴趣的同学可以参考相关资料学习。
截图的实现
shell命令实现
screencap命令用法如下screencap[-hp][FILENAME] -h:thismessage -p:savethefileasapng. IfFILENAMEendswith.pngitwillbesavedasapng. IfFILENAMEisnotgiven,theresultswillbeprintedtostdout.
如果文件名以.png结尾时,它将保存为png文件
如果文件名没有给出,则结果被会被输出到stdout
例如以下命令会将屏幕截图保存在sd卡路径下,文件名为screen.png
$adbshellscreencap-p/sdcard/screen.png
代码实现
截图工具类ScreenUtilspublicclassScreenUtils{ privateScreenUtils(){ /*cannotbeinstantiated*/ thrownewUnsupportedOperationException("cannotbeinstantiated"); } /** *获得屏幕高度 * *@paramcontext *@return */ publicstaticintgetScreenWidth(Contextcontext){ WindowManagerwm=(WindowManager)context .getSystemService(Context.WINDOW_SERVICE); DisplayMetricsoutMetrics=newDisplayMetrics(); wm.getDefaultDisplay().getMetrics(outMetrics); returnoutMetrics.widthPixels; } /** *获得屏幕宽度 * *@paramcontext *@return */ publicstaticintgetScreenHeight(Contextcontext){ WindowManagerwm=(WindowManager)context .getSystemService(Context.WINDOW_SERVICE); DisplayMetricsoutMetrics=newDisplayMetrics(); wm.getDefaultDisplay().getMetrics(outMetrics); returnoutMetrics.heightPixels; } /** *获得状态栏的高度 * *@paramcontext *@return */ publicstaticintgetStatusHeight(Contextcontext){ intstatusHeight=-1; try{ Class<?>clazz=Class.forName("com.android.internal.R$dimen"); Objectobject=clazz.newInstance(); intheight=Integer.parseInt(clazz.getField("status_bar_height") .get(object).toString()); statusHeight=context.getResources().getDimensionPixelSize(height); }catch(Exceptione){ e.printStackTrace(); } returnstatusHeight; } /** *获取当前屏幕截图,包含状态栏 * *@paramactivity *@return */ publicstaticBitmapsnapShotWithStatusBar(Activityactivity){ Viewview=activity.getWindow().getDecorView(); view.setDrawingCacheEnabled(true); view.buildDrawingCache(); Bitmapbmp=view.getDrawingCache(); intwidth=getScreenWidth(activity); intheight=getScreenHeight(activity); Bitmapbp=null; bp=Bitmap.createBitmap(bmp,0,0,width,height); view.destroyDrawingCache(); returnbp; } /** *获取当前屏幕截图,不包含状态栏 * *@paramactivity *@return */ publicstaticBitmapsnapShotWithoutStatusBar(Activityactivity){ Viewview=activity.getWindow().getDecorView(); view.setDrawingCacheEnabled(true); view.buildDrawingCache(); Bitmapbmp=view.getDrawingCache(); Rectframe=newRect(); activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); intstatusBarHeight=frame.top; intwidth=getScreenWidth(activity); intheight=getScreenHeight(activity); Bitmapbp=null; bp=Bitmap.createBitmap(bmp,0,statusBarHeight,width,height -statusBarHeight); view.destroyDrawingCache(); returnbp; } }
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
通过调用以上工具类的截图方法就可以拿到图片的bitmap然后就可以随心所欲的进行进一步操作了。
禁止截图的实现
禁止截图通过对window对象加标志位FLAG_SECURE实现,此标识位的注释如下,/**Windowflag:treatthecontentofthewindowassecure,preventing *itfromappearinginscreenshotsorfrombeingviewedonnon-secure *displays. * *<p>See{@linkandroid.view.Display#FLAG_SECURE}formoredetailsabout *securesurfacesandsecuredisplays. */ publicstaticfinalintFLAG_SECURE=0x00002000;
使用方式如下:
@Override protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); }
privatevoidinitializeScreenshotSecurity(){ if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.ICE_CREAM_SANDWICH&& TextSecurePreferences.isScreenSecurityEnabled(this)) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); }else{ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE); } }
相关文章推荐
- android应用里面在某个界面禁止系统截屏功能的实现
- [置顶] android应用中去android市场去评分的功能实现(吐槽一波个人应用上线...)
- iphone 应用内部实现截屏功能
- Android应用自动更新功能的实现!!!
- Android应用如何实现换主题功能
- Android应用自动更新功能的实现!!!
- iPhone 应用里实现截屏功能的代码
- Android应用如何实现换肤功能
- Android应用自动更新功能的实现!!!
- Android应用自动更新功能的实现
- AIR Native Extension:在Android的Flex应用中调用Android Intent实现分享功能
- Android 视频播放器截屏功能实现讲解
- Android应用如何实现换肤功能
- Android应用自动更新功能的实现!!! .(转自魏祝林博客)
- Android广播事件机制及应用(实现简单的定时提醒功能)
- Android:实现隐藏应用功能(续)
- Android应用之个人应用软件开发(3)【SQLite数据库及理财功能实现】
- iPhone 应用里实现截屏功能的代码
- iPhone 应用里实现截屏功能的代码
- Android下的应用编程——用HTTP协议实现文件上传功能