声明下,本文的内容仅用于技术讨论,不涉及到商业用途,如果用于商业用途请自行负责。
1 背景
最近无聊时,就去追小说玩,想使用免费的小说阅读软件,下载的时候阅读发现有Banner广告,这里多一句嘴,怎么实现bannner广告呢?(歪楼了,不过我想记录下,因为最近就用到过这个小的技巧,下一部分会提到)。继续说banner广告,特别烦,我司的app去年前的也是靠这个赚钱,去年年底考虑到用户体验就撤了,原因和我使用这个小说阅读软件类似,就是特别烦!!!
2 banner广告实现
貌似自己给自己挖坑。原理很简单,就是在 DecorView上添加view,因为该view是FrameLayout,故添加时,就在整个view的上层。这里再次歪下楼,android的几大布局中具有层次结构的FrameLayout, 还有个隐藏比较深的RelativeLayout,做动画的时候,奇葩的产品会有不同层次的设计。代码呢,请参考:http://blog.csdn.net/goodding/article/details/8562985。
这里给最主要的一句,中间省略细节处理。
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,然后在其上添加相应布局,于是这里就可以实现浮层引导页面,还有就是应用内悬浮窗口了,叨叨完。
3 正式进入反编译
再次重复使用我上篇提到的工具,//www.greatytc.com/p/d57c542b5949
这里我也介绍下,还有个反编译工具---jadx,这个阅读反编译出来的代码后,显示得到源代码,比较清晰,不像android killer 反编译后,查看源代码的jd 工具,代码条理较乱。怎么导入,本文省略,不了解请参考上篇。我们来看下,整个工程使用android killer 查看运行图如下:
看软件文件名就能猜到是哪家公司了,这里补一句,个人开发的小伙伴找不到图,就可以直接反编译下软件,在res资源下就是图片资源了,恩,注意这里仅仅是技术讨论。
1 这个软件用了哪些三方技术呢?
a 一看 alipay 你猜。
b baidu的
c google的是gson我这里不好截图,包太多了。
d multipletheme 这个就是切换主题的三方包,实现换肤功能。(感兴趣的小伙伴,可以详细阅读下这里)
e 还有就是侧滑的三方了,slidingmenu
f sina和qq的一看就是三方登录和分享了
2. 自己的技术呢?
恩,看文件,就知道ecom下面是广告,users下面是用户统计和crash分析等。reader就是该软件的工程主体代码部分。由于采用了混淆,故有些文件名称无法猜出。整体上看,软件的工程不是特别大,按照Android的一贯分层模式来划分包的。
4 去广告
终于来到我的目的地,去广告。这里吐血大放送,一个技巧。如何快速定位一个apk的界面。作为新人,我刚进公司要废很大劲找到对应的代码,最长达1个小时(我司工程项目较大,已经分包)。这里我提供两个简单的方法。
1 命令行形式
使用adb 命令行,需要简单配置下。 将adb调试下apk,进入想要查找的应用程序界面,然后cmd中输入adb shell。最后输入,以下的几个都可以:
a. 查看当前resume的是哪个activity: dumpsys activity | grep mResumedActivity
b.resume的Activity dumpsys activity | grep mFocusedActivity
c. 焦点view
adb shell dumpsys window windows | grep -E 'mCurrentFocus'
2 快速查找法
找到对应的关键词,找能代表该界面的关键词,这个点是逆向去广告,去支付的很常用方法。本文软件界面,除去广告提示词外,还有就是点击小说的中间位置时的工具栏里面的关键字。一个直接在android studio中查找(eclipse类似),另外一个是上篇提到的反编译工具中查找。
3正式进入去广告的activity---ActNovel
恩,这里顺便说一下,貌似开发人员命名很不规范,至少让我们这种不知道源码的阅读起来不方便,很严肃的事hao吗?
点击java源码的那个图标,进入jd 查看源码。
这里叨叨下,使用jadx的查看源码,大家感受下。
查找关键函数
看jadx上的截图,程序猿大哥这次写的很明白呀。恩,有人一定会问,那万一遇到不能猜出来的怎么办呢?很简单,使用本文提到的快速定位法,比如,本文想去掉这个页面广告,点击×,看弹出的窗口提示文字,快速反定位到函数。当然本文去广告的点很多,jadx上的是addAdsView()从整体上。还有其他地方可以去广告的点。看下源代码:
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);
}
}
}
想去广告点很多呀,
(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函数里面不显示广告也可以。
ok,来找到smali源代码。
进入对应函数:
.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
关键点如下:
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掉呗,恩,这里挖了个坑等大家。整个过程结束了,码字挺辛苦的,各位看官有收获点个赞呗!