日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一种实现(无须root)手机截屏方案

發布時間:2025/3/15 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一种实现(无须root)手机截屏方案 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載請把頭部出處鏈接和尾部二維碼一起轉載,本文出自逆流的魚yuiop:http://blog.csdn.net/hejjunlin/article/details/53966818

前言:一年半多以前,我們曾有個項目,要做一個截屏功能,當時負責調研的同事,答應了產品上這個功能,但開發一周后,發現,無法實現截取手機屏幕圖像,須要root權限,才能做。因為最近研究MediaProjection,意外的發現,竟然無須root,可以輕松實現次功能。曾經被做不到的,如今做到了,很難相信此時的心情??聪陆裉斓腁genda:

  • Android源碼中使用組合鍵是如何實現屏幕截圖功能的?
  • MediaProjection實現手機截屏效果
  • 簡要思路

以我的魅族手機為例,是同時按電源鍵+音量下鍵來實現截屏,蘋果手機則是電源鍵 + HOME鍵,小米手機是菜單鍵+音量下鍵,而HTC一般是按住電源鍵再按左下角的“主頁”鍵。那么Android源碼中使用組合鍵是如何實現屏幕截圖功能呢?

Android源碼中對按鍵的捕獲位于文件PhoneWindowManager.java中?


?

這個類處理所有的按鍵事件,其中函數interceptKeyBeforeQueueing()會對常用的按鍵做特殊處理。以我自己魅族手機為例,是同時按電源鍵和音量下鍵來截屏,那么在這個方法中可以看到這么如下代碼:?
interceptKeyBeforeQueueing?

?

以上代碼總結為:當按下音量下鍵時,且是down時,會進入到interceptPowerKeyDown方法中,而按下電源鍵時,且是down時,也會進入interceptPowerKeyDown方法中,接著進入這個方法中看下:?
interceptPowerKeyDown?

?

以上代碼總結為:如果是interactive為true,且一些其他條件滿足時,會記錄電源鍵按下的時間,且進入interceptScreenshotChord方法中:?

?

以上代碼總結為:用兩個布爾變量判斷是否同時按了音量下鍵和電源鍵后,再計算兩個按鍵響應Down事件之間的時間差不超過( // Time to volume and power must be pressed within this interval of each other.?
private static final long SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS = 150;)150毫秒,也就認為是同時按了這兩個鍵后,此種case時,才是真正的屏幕截屏的組合鍵。

獲取到組合鍵后,會用一個mHandler 開始post一個runnable,進入這個runnable中:?


?

以上代碼,會執行方法takeScreenshot方法,接著進入:?

?

以上代碼總結為:使用AIDL綁定了service服務到”com.android.systemui.screenshot.TakeScreenshotService”,注意在service連接成功時,對message的msg.arg1和msg.arg2兩個參數的賦值。其中在mScreenshotTimeout中對服務service做了超時處理。接著我們找到實現這個服務service的類TakeScreenshotService,該類在(frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot包下):?

?

對應代碼如下:?

?

以上代碼總結為:引用了GlobalScreenshot類,調用了takeScreenshot方法,緊接著進入:?

?

以上代碼總結為:引用SurfaceControl類,調用了screenshot方法, 傳入了屏幕的寬和高,這兩個參數,接著進入SurfaceControl類中,位于frameworks/base/core/java/android/view目錄下:?

?

對應screenshot方法代碼如下:?

?

screenshot?

?

最終到達native方法中nativeScreenshot?

?

上面就是java層的部分,接著到jni層,在\frameworks\base\core\jni\android_view_SurfaceControl.cpp中:?

?

以上代碼總結為:到jni中,映射nativeScreenshot方法的是nativeScreenshotBitmap函數,這個函數代碼如下:?

?
?

以上代碼總結為:實例化ScreenshotClient類,且調用update方法,最終通過構造一個新的bitmap,把screenshot得到的像素點,及相關信息達到bitmap,通過GraphicsJNI,重新創建一個bitmap返回給上層。?
我們接著看下ScreenshotClient的聲明,位于SurfaceComposerClient.h中。注意這個類是在frameworks\native\include\gui中,而前面android_view_SurfaceControl是在\frameworks\base\core\jni\下?

?

最后輾轉來到c++層,就是\frameworks\native\libs\gui下的SurfaceComposerClient.cpp中,實現ScreenshotClient聲明的函數update,如下:?

?

以上代碼總結為:通過ISurfaceComposer接口,調用captureScreen函數,我們找到其對應的實現類\frameworks\native\libs\gui\ISurfaceComposer.cpp,找到captureScreen函數的實現如下:?

?

以上代碼總結為:把IGraphicBufferProducer,作為binder開始寫到parcel中,最后一版看到transact,就知道當前是client端,而server端的onTransact()函數,會接收到傳過來的參數。如這里的data。接著看下BnSurfaceComposer的onTransact方法,這個BnSurfaceComposer依然是在ISurfaceComposer.cpp中。?

?

以上代碼總結為:當進入到CAPTURE_SCREEN中,data會讀取IGraphicBufferProducer生成出的圖像buffe,接著調用 reply->writeInt32(res);返回給client.然后再回調到java層。以上就是系統截屏的原理。

那對于多媒體這塊可以通過MediaProjection+VirturalDisplay+MediaProjectionManager來實現截屏,以下我的實例效果圖:

效果圖1:操作過程,點擊浮動小剪刀,就可以實現截屏,拖動小剪刀,可到任意位置:?


?

效果圖2:截圖后過程?


?

主界面:?


?

體驗apk:?
鏈接:http://pan.baidu.com/s/1kVugxCV?密碼:97z0

實現思路:

  • MediaProjection是一個token,用戶可以授予應用程序捕獲屏幕內容和錄制系統音頻。
  • 屏幕截取,可以通過MediaProjectionManager的createScreenCaptureIntent,創建一個intent,保證有足夠能力截取屏幕上的內容,但是沒有系統聲音。
  • 調用setUpMediaProjection()方法獲取共享數據并對其進行賦值;若已初始化,則直接調用virtualDisplay()方法利用之前定義的變量對截屏環境進行初始化。

第一時間獲得博客更新提醒,以及更多android干貨,源碼分析,歡迎關注我的微信公眾號,掃一掃下方二維碼或者長按識別二維碼,即可關注。


如果你覺得好,隨手點贊,也是對筆者的肯定,也可以分享此公眾號給你更多的人,原創不易 與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的一种实现(无须root)手机截屏方案的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。