#由來: 最近項目要接入各類支付,其中一個是銀聯支付。因而開始搗鼓,以前也沒接入過,只是作過微信和支付寶。 下載銀聯的SDK、Demo、文檔等等若干東西開始啃,一打開文檔,發現100多頁。。。因而瞬間就不想看了,隨便翻了翻,全都是方案規範什麼的,頭都大了,因而開始搗鼓SDK和Demo。 老樣子,先把Demo跑起來(此處省略若干字)。java
跑起來後的銀聯demo首頁如圖所示:android
好了如今開始測試一波,使用銀聯提供的測試卡號和手機號以及驗證碼,開始付款,上截圖:git
WTF??(黑人問號),爲什麼AS的截圖一直菊花,進不去截圖界面?估計是ADB歇菜了吧(自從AS2.2正式版+Sieera正式版)發佈後,adb一直有問題。好吧我重啓ASgithub
。。。仍是不行,一直菊花! 好吧,我用手機自帶的截圖: 安全
沒法進行屏幕截圖,緣由多是存儲空間不足,或者該應用或您所屬的單位不容許執行此操做。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
祭出誅仙劍以後,開始嘗試尋找支付界面的類名和包名(快看左上角快看左上角):測試
能夠看到,包名是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);