聲明下跨嘉,本文的內(nèi)容僅用于技術(shù)討論,不涉及到商業(yè)用途亡笑,如果用于商業(yè)用途請自行負(fù)責(zé)侣夷。
1 背景
最近無聊時,就去追小說玩仑乌,想使用免費(fèi)的小說閱讀軟件百拓,下載的時候閱讀發(fā)現(xiàn)有Banner廣告,這里多一句嘴晰甚,怎么實現(xiàn)bannner廣告呢衙传?(歪樓了,不過我想記錄下厕九,因為最近就用到過這個小的技巧蓖捶,下一部分會提到)。繼續(xù)說banner廣告扁远,特別煩俊鱼,我司的app去年前的也是靠這個賺錢,去年年底考慮到用戶體驗就撤了畅买,原因和我使用這個小說閱讀軟件類似并闲,就是特別煩!9刃摺帝火!
2 banner廣告實現(xiàn)
貌似自己給自己挖坑。原理很簡單湃缎,就是在 DecorView上添加view购公,因為該view是FrameLayout,故添加時,就在整個view的上層雁歌。這里再次歪下樓宏浩,android的幾大布局中具有層次結(jié)構(gòu)的FrameLayout, 還有個隱藏比較深的RelativeLayout靠瞎,做動畫的時候比庄,奇葩的產(chǎn)品會有不同層次的設(shè)計。代碼呢乏盐,請參考:http://blog.csdn.net/goodding/article/details/8562985佳窑。
這里給最主要的一句,中間省略細(xì)節(jié)處理父能。
addFloatView((FrameLayout) getWindow().getDecorView());
private void addFloatView(FrameLayout parent) {
if (mFloatView == null || (mFloatView.getParent() == null)) {
if (!mIsAdded) {
initFloatView();
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
parent.addView(mFloatView,lp);
mIsAdded = true;
}
}
}
很簡單神凑,就是拿到DecorView,然后在其上添加相應(yīng)布局,于是這里就可以實現(xiàn)浮層引導(dǎo)頁面溉委,還有就是應(yīng)用內(nèi)懸浮窗口了鹃唯,叨叨完。
3 正式進(jìn)入反編譯
再次重復(fù)使用我上篇提到的工具瓣喊,http://www.reibang.com/p/d57c542b5949
這里我也介紹下坡慌,還有個反編譯工具---jadx,這個閱讀反編譯出來的代碼后藻三,顯示得到源代碼洪橘,比較清晰,不像android killer 反編譯后棵帽,查看源代碼的jd 工具熄求,代碼條理較亂。怎么導(dǎo)入逗概,本文省略抡四,不了解請參考上篇。我們來看下仗谆,整個工程使用android killer 查看運(yùn)行圖如下:
看軟件文件名就能猜到是哪家公司了指巡,這里補(bǔ)一句,個人開發(fā)的小伙伴找不到圖隶垮,就可以直接反編譯下軟件藻雪,在res資源下就是圖片資源了,恩狸吞,注意這里僅僅是技術(shù)討論勉耀。
1 這個軟件用了哪些三方技術(shù)呢?
a 一看 alipay 你猜蹋偏。
b baidu的
c google的是gson我這里不好截圖便斥,包太多了。
d multipletheme 這個就是切換主題的三方包威始,實現(xiàn)換膚功能枢纠。(感興趣的小伙伴,可以詳細(xì)閱讀下這里)
e 還有就是側(cè)滑的三方了黎棠,slidingmenu
f sina和qq的一看就是三方登錄和分享了
2. 自己的技術(shù)呢晋渺?
恩,看文件脓斩,就知道ecom下面是廣告木西,users下面是用戶統(tǒng)計和crash分析等。reader就是該軟件的工程主體代碼部分随静。由于采用了混淆八千,故有些文件名稱無法猜出。整體上看,軟件的工程不是特別大恋捆,按照Android的一貫分層模式來劃分包的照皆。
4 去廣告
終于來到我的目的地,去廣告鸠信。這里吐血大放送,一個技巧论寨。如何快速定位一個apk的界面星立。作為新人,我剛進(jìn)公司要廢很大勁找到對應(yīng)的代碼葬凳,最長達(dá)1個小時(我司工程項目較大绰垂,已經(jīng)分包)。這里我提供兩個簡單的方法火焰。
1 命令行形式
使用adb 命令行劲装,需要簡單配置下。 將adb調(diào)試下apk昌简,進(jìn)入想要查找的應(yīng)用程序界面占业,然后cmd中輸入adb shell。最后輸入纯赎,以下的幾個都可以:
a. 查看當(dāng)前resume的是哪個activity: dumpsys activity | grep mResumedActivity
b.resume的Activity dumpsys activity | grep mFocusedActivity
c. 焦點(diǎn)view
adb shell dumpsys window windows | grep -E 'mCurrentFocus'
2 快速查找法
找到對應(yīng)的關(guān)鍵詞谦疾,找能代表該界面的關(guān)鍵詞,這個點(diǎn)是逆向去廣告犬金,去支付的很常用方法念恍。本文軟件界面,除去廣告提示詞外晚顷,還有就是點(diǎn)擊小說的中間位置時的工具欄里面的關(guān)鍵字峰伙。一個直接在android studio中查找(eclipse類似),另外一個是上篇提到的反編譯工具中查找该默。
3正式進(jìn)入去廣告的activity---ActNovel
恩瞳氓,這里順便說一下,貌似開發(fā)人員命名很不規(guī)范栓袖,至少讓我們這種不知道源碼的閱讀起來不方便顿膨,很嚴(yán)肅的事hao嗎?
點(diǎn)擊java源碼的那個圖標(biāo)叽赊,進(jìn)入jd 查看源碼恋沃。
這里叨叨下,使用jadx的查看源碼,大家感受下必指。
查找關(guān)鍵函數(shù)
看jadx上的截圖囊咏,程序猿大哥這次寫的很明白呀。恩,有人一定會問,那萬一遇到不能猜出來的怎么辦呢榛了?很簡單丐怯,使用本文提到的快速定位法,比如泌类,本文想去掉這個頁面廣告,點(diǎn)擊×底燎,看彈出的窗口提示文字刃榨,快速反定位到函數(shù)。當(dāng)然本文去廣告的點(diǎn)很多双仍,jadx上的是addAdsView()從整體上枢希。還有其他地方可以去廣告的點(diǎn)≈煳郑看下源代碼:
private void addAdsView() {
if (com.esbook.reader.a.a.E != 0 && !this.isClosed) {
this.isAdShowing = true;
this.adContainer.removeAllViews();
if (this.easouAdUtils == null) {
this.easouAdUtils = new bo(getApplicationContext(), this, this.adContainer, com.esbook.reader.a.a.L, com.esbook.reader.a.a.K, MSG_LOAD_NEXT_CHAPTER);
this.easouAdUtils.a(new ca(this));
this.easouAdUtils.a(new cb(this));
} else {
this.easouAdUtils.a(this.adContainer, this.easouAdUtils.b());
}
if (this.ad_coverview == null) {
this.ad_coverview = new View(getApplicationContext());
this.ad_coverview.setBackgroundColor(getResources().getColor(R.color.transparent_ad));
}
ViewGroup viewGroup = (ViewGroup) this.ad_coverview.getParent();
if (viewGroup != null) {
viewGroup.removeAllViews();
}
this.adContainer.addView(this.ad_coverview, new LayoutParams(-1, -1));
if (com.esbook.reader.a.a.j == MSG_LOAD_PRE_CHAPTER || com.esbook.reader.a.a.j == MSG_CHANGE_SOURCE || com.esbook.reader.a.a.j == ERROR) {
showAdCover(true);
} else {
showAdCover(false);
}
}
}
想去廣告點(diǎn)很多呀苞轿,
(1)從一開始就return,不添加逗物。
(2)還有就是:
if (com.esbook.reader.a.a.j == MSG_LOAD_PRE_CHAPTER || com.esbook.reader.a.a.j == MSG_CHANGE_SOURCE || com.esbook.reader.a.a.j == ERROR) {
showAdCover(true);
} else {
showAdCover(false);
}
都showAdCover(false)
(3) showAdCover函數(shù)里面不顯示廣告也可以搬卒。
ok,來找到smali源代碼翎卓。
進(jìn)入對應(yīng)函數(shù):
.method private addAdsView()V
.locals 9
const/4 v8, -0x1
const/4 v7, 0x1
sget v0, Lcom/esbook/reader/a/a;->E:I
if-eqz v0, :cond_0
iget-boolean v0, p0, Lcom/esbook/reader/activity/ActNovel;->isClosed:Z
if-eqz v0, :cond_1
:cond_0
:goto_0
return-void
:cond_1
iput-boolean v7, p0, Lcom/esbook/reader/activity/ActNovel;->isAdShowing:Z
iget-object v0, p0, Lcom/esbook/reader/activity/ActNovel;->adContainer:Landroid/widget/RelativeLayout;
invoke-virtual {v0}, Landroid/widget/RelativeLayout;->removeAllViews()V
iget-object v0, p0, Lcom/esbook/reader/activity/ActNovel;->easouAdUtils:Lcom/esbook/reader/util/bo;
if-nez v0, :cond_5
new-instance v0, Lcom/esbook/reader/util/bo;
invoke-virtual {p0}, Lcom/esbook/reader/activity/ActNovel;->getApplicationContext()Landroid/content/Context;
move-result-object v1
iget-object v3, p0, Lcom/esbook/reader/activity/ActNovel;->adContainer:Landroid/widget/RelativeLayout;
sget v4, Lcom/esbook/reader/a/a;->L:I
sget v5, Lcom/esbook/reader/a/a;->K:I
const/4 v6, 0x2
move-object v2, p0
invoke-direct/range {v0 .. v6}, Lcom/esbook/reader/util/bo;-><init>(Landroid/content/Context;Landroid/app/Activity;Landroid/widget/RelativeLayout;III)V
iput-object v0, p0, Lcom/esbook/reader/activity/ActNovel;->easouAdUtils:Lcom/esbook/reader/util/bo;
iget-object v0, p0, Lcom/esbook/reader/activity/ActNovel;->easouAdUtils:Lcom/esbook/reader/util/bo;
new-instance v1, Lcom/esbook/reader/activity/ca;
invoke-direct {v1, p0}, Lcom/esbook/reader/activity/ca;-><init>(Lcom/esbook/reader/activity/ActNovel;)V
invoke-virtual {v0, v1}, Lcom/esbook/reader/util/bo;->a(Lcom/esbook/reader/util/bq;)V
iget-object v0, p0, Lcom/esbook/reader/activity/ActNovel;->easouAdUtils:Lcom/esbook/reader/util/bo;
new-instance v1, Lcom/esbook/reader/activity/cb;
invoke-direct {v1, p0}, Lcom/esbook/reader/activity/cb;-><init>(Lcom/esbook/reader/activity/ActNovel;)V
invoke-virtual {v0, v1}, Lcom/esbook/reader/util/bo;->a(Lcom/esbook/reader/util/bs;)V
:goto_1
iget-object v0, p0, Lcom/esbook/reader/activity/ActNovel;->ad_coverview:Landroid/view/View;
if-nez v0, :cond_2
new-instance v0, Landroid/view/View;
invoke-virtual {p0}, Lcom/esbook/reader/activity/ActNovel;->getApplicationContext()Landroid/content/Context;
move-result-object v1
invoke-direct {v0, v1}, Landroid/view/View;-><init>(Landroid/content/Context;)V
iput-object v0, p0, Lcom/esbook/reader/activity/ActNovel;->ad_coverview:Landroid/view/View;
iget-object v0, p0, Lcom/esbook/reader/activity/ActNovel;->ad_coverview:Landroid/view/View;
invoke-virtual {p0}, Lcom/esbook/reader/activity/ActNovel;->getResources()Landroid/content/res/Resources;
move-result-object v1
const v2, 0x7f090013
invoke-virtual {v1, v2}, Landroid/content/res/Resources;->getColor(I)I
move-result v1
invoke-virtual {v0, v1}, Landroid/view/View;->setBackgroundColor(I)V
:cond_2
iget-object v0, p0, Lcom/esbook/reader/activity/ActNovel;->ad_coverview:Landroid/view/View;
invoke-virtual {v0}, Landroid/view/View;->getParent()Landroid/view/ViewParent;
move-result-object v0
check-cast v0, Landroid/view/ViewGroup;
if-eqz v0, :cond_3
invoke-virtual {v0}, Landroid/view/ViewGroup;->removeAllViews()V
:cond_3
iget-object v0, p0, Lcom/esbook/reader/activity/ActNovel;->adContainer:Landroid/widget/RelativeLayout;
iget-object v1, p0, Lcom/esbook/reader/activity/ActNovel;->ad_coverview:Landroid/view/View;
new-instance v2, Landroid/widget/RelativeLayout$LayoutParams;
invoke-direct {v2, v8, v8}, Landroid/widget/RelativeLayout$LayoutParams;-><init>(II)V
invoke-virtual {v0, v1, v2}, Landroid/widget/RelativeLayout;->addView(Landroid/view/View;Landroid/view/ViewGroup$LayoutParams;)V
sget v0, Lcom/esbook/reader/a/a;->j:I
if-eq v0, v7, :cond_4
sget v0, Lcom/esbook/reader/a/a;->j:I
const/4 v1, 0x4
if-eq v0, v1, :cond_4
sget v0, Lcom/esbook/reader/a/a;->j:I
const/4 v1, 0x7
if-ne v0, v1, :cond_6
:cond_4
invoke-direct {p0, v7}, Lcom/esbook/reader/activity/ActNovel;->showAdCover(Z)V
goto :goto_0
:cond_5
iget-object v0, p0, Lcom/esbook/reader/activity/ActNovel;->easouAdUtils:Lcom/esbook/reader/util/bo;
iget-object v1, p0, Lcom/esbook/reader/activity/ActNovel;->adContainer:Landroid/widget/RelativeLayout;
iget-object v2, p0, Lcom/esbook/reader/activity/ActNovel;->easouAdUtils:Lcom/esbook/reader/util/bo;
invoke-virtual {v2}, Lcom/esbook/reader/util/bo;->b()I
move-result v2
invoke-virtual {v0, v1, v2}, Lcom/esbook/reader/util/bo;->a(Landroid/widget/RelativeLayout;I)V
goto :goto_1
:cond_6
const/4 v0, 0x0
invoke-direct {p0, v0}, Lcom/esbook/reader/activity/ActNovel;->showAdCover(Z)V
goto/16 :goto_0
.end method
關(guān)鍵點(diǎn)如下:
sget v0, Lcom/esbook/reader/a/a;->E:I
if-eqz v0, :cond_0
iget-boolean v0, p0, Lcom/esbook/reader/activity/ActNovel;->isClosed:Z
if-eqz v0, :cond_1
:cond_0
if-eq v0, v1, :cond_4
sget v0, Lcom/esbook/reader/a/a;->j:I
const/4 v1, 0x7
if-ne v0, v1, :cond_6
:cond_4
invoke-direct {p0, v7}, Lcom/esbook/reader/activity/ActNovel;->showAdCover(Z)V
goto :goto_0
:cond_5
iget-object v0, p0, Lcom/esbook/reader/activity/ActNovel;->easouAdUtils:Lcom/esbook/reader/util/bo;
iget-object v1, p0, Lcom/esbook/reader/activity/ActNovel;->adContainer:Landroid/widget/RelativeLayout;
iget-object v2, p0, Lcom/esbook/reader/activity/ActNovel;->easouAdUtils:Lcom/esbook/reader/util/bo;
invoke-virtual {v2}, Lcom/esbook/reader/util/bo;->b()I
move-result v2
invoke-virtual {v0, v1, v2}, Lcom/esbook/reader/util/bo;->a(Landroid/widget/RelativeLayout;I)V
goto :goto_1
:cond_6
const/4 v0, 0x0
invoke-direct {p0, v0}, Lcom/esbook/reader/activity/ActNovel;->showAdCover(Z)V
goto/16 :goto_0
對著源代碼秀睛,還是很容易閱讀。 怎么去莲祸,簡單的nop掉唄蹂安,恩,這里挖了個坑等大家锐帜。整個過程結(jié)束了田盈,碼字挺辛苦的,各位看官有收獲點(diǎn)個贊唄缴阎!