讓你的app沒法使用系統截圖的探究

#由來: 最近項目要接入各類支付,其中一個是銀聯支付。因而開始搗鼓,以前也沒接入過,只是作過微信和支付寶。 下載銀聯的SDK、Demo、文檔等等若干東西開始啃,一打開文檔,發現100多頁。。。因而瞬間就不想看了,隨便翻了翻,全都是方案規範什麼的,頭都大了,因而開始搗鼓SDK和Demo。 老樣子,先把Demo跑起來(此處省略若干字)。java

跑起來後的銀聯demo首頁如圖所示:android

首頁.png

好了如今開始測試一波,使用銀聯提供的測試卡號和手機號以及驗證碼,開始付款,上截圖:git

截圖.png

WTF??(黑人問號),爲什麼AS的截圖一直菊花,進不去截圖界面?估計是ADB歇菜了吧(自從AS2.2正式版+Sieera正式版)發佈後,adb一直有問題。好吧我重啓ASgithub

。。。仍是不行,一直菊花! 好吧,我用手機自帶的截圖: 安全

什麼鬼.jpg

沒法進行屏幕截圖,緣由多是存儲空間不足,或者該應用或您所屬的單位不容許執行此操做。bash

黑人問號??這是什麼鬼,還能這樣?微信


#開始探究 對!前面說了這麼多廢話,就是爲了給這個東西作鋪墊。 開始分析一波:這東西在銀聯Demo裏存在,首頁上面已經截圖了,證實沒問題,有問題的是開始支付以後的全部界面,開始猜想:由於支付涉及到的東西比較複雜,尤爲是隱私和安全性,因此這些東西通常都是被封裝起來的,對外提供爲混淆後的jar包。 去驗證一波,先找到Demo中支付的按鈕所觸發的動做:app

public class JARActivity extends BaseActivity {    
    @Override    
    public void doStartUnionPayPlugin(Activity activity, String tn, String mode) {        
         UPPayAssistEx.startPay(activity, null, null, tn, mode);    
    }    
    //省略部分代碼...
}
複製代碼

能夠看到,發起支付以後,到了UPPayAssistEx.startPay()方法去了,而這個方法正好是在SDK的jar包內。 也就是說致使咱們無法截屏的代碼在SDK中,有多是C層面控制的(畢竟有so),也有多是Android本身控制的,提供了API。 C層面的很差找,因此先看看是不是Android的API吧。 組織咱們截屏,也就是說在xxxActivity下,咱們沒辦法得到這個Activity的「信息」,因此先去看看支付的Activity是怎麼寫的吧。 這裏要祭出神器了:TopActivity.apk 我從事Android開發一年,這個東西也伴隨了我一年,他能夠獲取當前運行的apk的Activity名字以及包名,這個app被做者開源在了Githubide


祭出誅仙劍以後,開始嘗試尋找支付界面的類名和包名(快看左上角快看左上角):測試

類名和包名.jpg

能夠看到,包名是com.unionpay.uppay,Activity名字是PayActivity。 OK,有了這些信息,開始去SDK中尋找:

public final class PayActivity extends BaseActivity {    
      private b c = null;    
      private f d = null;   
      private n e;    
      public static String a;   
      private k f = null;   

      public PayActivity() {}    
      public final void onCreate(Bundle var1) {        
          super.onCreate(var1);    
     }
      //省略部分代碼...
}
複製代碼

找到了這個支付界面的Activity,通常來講要對窗口進行操做,須要在 onCreate() 中,可是這個Activity的onCreate()是調用父類的方法。其實也很正常,畢竟是有個基類的Activity,因此咱們看看BaseActivity:

public abstract class BaseActivity extends 
        Activity implements com.unionpay.mobile.android.plugin.a, b {    
      //省略部分代碼...
      public void onCreate(Bundle var1) { 
           //省略部分代碼...       
           UPAgent.LOG_ON = false;
           this.requestWindowFeature(1);
           super.onCreate(var1);
           this.c = (l)this.a(1, (e)null);
           this.setContentView(this.c);
           this.getWindow().addFlags(8192);
           ++f;
           //省略部分代碼...
      }    
//省略部分代碼...
}
複製代碼

好了,這個就是銀聯支付全部Activity的父類了,畢竟繼承了Activity。 分析下有沒有什麼有用的線索: 發現一個東西:this.getWindow().addFlags(8192);。這個和咱們以前的假設差很少,由於Activity和window有極大的關係,不少操做都要依靠getWindow()來進行,好比去掉標題欄之類的。那麼這個8912是什麼鬼? Android中的這種系統常量通常都是16進制的,因此咱們把這個8192轉換成16進制看看是多少:

0x2000

由於這個常量是給window的,回想一下以前咱們設置全屏:

this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

因此咱們進入到WindowManager.LayoutParams去看看,搜索常量先。 搜索2000

/** Window flag: treat the content of the window as secure, preventing * it from appearing in screenshots or from being viewed on non-secure * displays. * * <p>See {@link android.view.Display#FLAG_SECURE} for more details about * secure surfaces and secure displays. */
public static final int FLAG_SECURE             = 0x00002000;
複製代碼

**NICE!**看這個變量名字就知道了,FLAG_SECURE->安全。固然不能依照名字來判定,仍是看看註釋。這上面說:這個標誌是用來將窗口內容視爲安全的,它不會出如今屏幕截圖裏面。


也就是說:咱們本身的Activity,只要加上了這個標誌,就會變得「安全」,不會被屏幕截圖捕捉到,即便是adb命令。


驗證以後,果真如此,AS獲取不到屏幕截圖,手機自帶的截屏也拿不到了,豌豆莢等第三方客戶端暫時沒測試,電腦上沒有豌豆莢,感興趣的朋友能夠試試看。

#結語 想要像銀聯同樣,在某Activity作到手機沒法截屏,甚至是adb也拿不到,那麼能夠在Activity中加入: getWindow().addFlags(WindowManager.LayoutParams. FLAG_SECURE);

相關文章
相關標籤/搜索