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

yangxingye 8年前發布 | 9K 次閱讀 安卓開發 Android開發 移動開發

由來:

最近項目要接入各種支付,其中一個是銀聯支付。于是開始搗鼓,之前也沒接入過,只是做過微信和支付寶。

下載銀聯的SDK、Demo、文檔等等若干東西開始啃,一打開文檔,發現100多頁。。。于是瞬間就不想看了,隨便翻了翻,全都是方案規范什么的,頭都大了,于是開始搗鼓SDK和Demo。

老樣子,先把Demo跑起來(此處省略若干字)。

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

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

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

。。。還是不行,一直菊花!

好吧,我用手機自帶的截圖:

無法進行屏幕截圖,原因可能是存儲空間不足,或者該應用或您所屬的單位不允許執行此操作。

黑人問號??這是什么鬼,還能這樣?

開始探究

對!前面說了這么多廢話,就是為了給這個東西做鋪墊。

開始分析一波:這東西在銀聯Demo里存在,首頁上面已經截圖了,證明沒問題,有問題的是開始支付之后的所有界面, 開始猜測:因為支付涉及到的東西比較復雜,尤其是隱私和安全性,所以這些東西一般都是被封裝起來的,對外提供為混淆后的jar包。

去驗證一波,先找到Demo中支付的按鈕所觸發的動作:

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名字以及包名。

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

可以看到,包名是 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);    
 }
  //省略部分代碼...

}</code></pre>

找到了這個支付界面的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進制看看是多少:

0×2000

因為這個常量是給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;</code></pre>

    NICE!看這個變量名字就知道了, FLAG_SECURE->安全 。當然不能依照名字來斷定,還是看看注釋。這上面說: 這個標志是用來將窗口內容視為安全的,它不會出現在屏幕截圖里面。

    也就是說:我們自己的Activity,只要加上了這個標志,就會變得“安全”,不會被屏幕截圖捕捉到,即使是adb命令。

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

    結語

    想要像銀聯一樣,在某Activity做到手機無法截屏,甚至是adb也拿不到,那么可以在Activity中加入:

    getWindow().addFlags(WindowManager.LayoutParams. FLAG_SECURE);

     

     

    來自:http://www.androidchina.net/5938.html

     

 本文由用戶 yangxingye 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!