如何防止广告拦截器在应用程序中拦截广告

60

我的一位用户向我透露,他们正在使用我的免费应用程序,该应用程序通过广告实现盈利,但是他们正在使用广告拦截器来屏蔽广告。他嘲讽地告诉我这个信息,好像我对此无能为力。

我能否采取措施解决这个问题?有没有办法检测到广告被拦截了?


你能否检查是否安装了广告拦截器,如果有,请显示一个对话框,提示用户禁用拦截器,否则程序将无法运行? - Mike
我完全不知道,但是想到有人这样做就让我感到恶心。我需要了解每一个现有的广告拦截器,所以我认为这个解决方案并不好。 - Christopher Perry
6
另一个选项是在广告背后放置带有您的商标或其他标识的图片,以及一个按钮,将引导他们前往您的市场页面或某种广告宣传。因此,即使广告没有显示出来,他们仍然会看到您的产品广告。听起来好像那个人只是想找茬。 - Mike
根据我在Android市场的经验,这远远不足以弥补我的时间成本。大多数Android用户在有免费版本的情况下不会购买应用程序,这就是为什么我选择通过广告实现盈利的原因。 - Christopher Perry
这个问题的标题怎么了 o.O? - Some Noob Student
15个回答

61

我知道一种广告拦截的方式(适用于任何计算机),就是编辑 hosts 文件,将所有已知的广告服务器指向本地主机。在 Android 上,这个文件位于“etc/hosts”。

例如,我使用 AdMob 广告,一个来自自定义 ROM 列表的 host 文件列出了以下的 AdMob 条目:

127.0.0.1 analytics.admob.com
127.0.0.1 mmv.admob.com
127.0.0.1 mm.admob.com
127.0.0.1 admob.com
127.0.0.1 a.admob.com
127.0.0.1 jp.admob.com
127.0.0.1 c.admob.com
127.0.0.1 p.admob.com
127.0.0.1 mm1.vip.sc1.admob.com
127.0.0.1 media.admob.com
127.0.0.1 e.admob.com
现在,任何时候,当一个进程试图解析以上地址时,它们都会被路由到其左侧列出的地址(本地主机),在这种情况下。
我的应用程序中,我会检查此主机文件并查找任何admob条目,如果我发现任何条目,我会通知用户我已检测到广告拦截并告诉他们从那里删除admob条目,并不允许他们使用该应用程序。
毕竟,如果他们看不到广告,那我有什么好处呢?没有必要让他们免费使用该应用程序。
以下是我实现这一点的代码片段:
        BufferedReader in = null;

    try 
    {
        in = new BufferedReader(new InputStreamReader(
                new FileInputStream("/etc/hosts")));
        String line;

        while ((line = in.readLine()) != null)
        {
            if (line.contains("admob"))
            {
                result = false;
                break;
            }
        }
    } 

我发誓所有广告支持的应用程序都应该检查此文件。您不需要以root身份访问它,但写入它可能会有所不同。

此外,不确定是否有其他文件在基于Linux的操作系统上起着相同的作用,但无论如何,我们都可以检查所有这些文件。

欢迎任何改进建议。

还有一个名为“Ad Free Android”的应用程序需要root访问权限,这意味着它很可能会更改hosts文件以实现其目标。


3
太高兴了,我不是唯一这样做的人......我感到有些内疚,但同时,我不明白为什么如果我选择与广告共享我的代码,就会有人屏蔽它们,从而完全消除我最初免费分享个人代码的动力。在开始这样做之前,我曾真诚地考虑只发布iPhone应用程序。 - AndrewPK
4
请注意检查一下相关行是否被注释掉了。if (line.contains("admob"))应该改为if(line.contains("admob") && !line.matches("^ *#"))。改动后意思保持不变,但请确保语言更加通俗易懂。 - Kevin Mark
经过测试发现,我需要使用编译后的模式和匹配器,否则它永远不会匹配。很奇怪。 - Kevin Mark
谢谢,我正在使用这个解决方案。并显示一个比普通横幅更大的布局块,其中包含一段长文本,告知用户为什么需要广告。它运作得非常好 :) - EvanBlack

23

我为此问题的代码如下:

try {
    if (InetAddress.getByName("a.admob.com").getHostAddress().equals("127.0.0.1") ||
        InetAddress.getByName("mm.admob.com").getHostAddress().equals("127.0.0.1") ||
        InetAddress.getByName("p.admob.com").getHostAddress().equals("127.0.0.1") ||
        InetAddress.getByName("r.admob.com").getHostAddress().equals("127.0.0.1")) {
        //Naughty Boy - Punishing code goes here.
        // In my case its a dialog which goes to the pay-for version 
        // of my application in the market once the dialog is closed.
    }
} catch (UnknownHostException e) { } //no internet

希望能有所帮助。


15
-1 是因为可以通过将这些网站重定向到 127.0.0.2 或 240.240.240.240 轻松地被黑客攻击。AdFree 允许您选择 IP 地址 :D。当然,我的意思是建设性的,而不是惩罚性的。 - usr-local-ΕΨΗΕΛΩΝ

11
作为开发者,我们需要尽力理解用户,并在惩罚少数试图占便宜的用户和遵循规则的大多数用户之间找到一个平衡点。移动广告是一种合理的方式,可以让用户免费使用功能齐全的软件。使用广告拦截技术的用户可能会被视为失去的收入,但如果你从更大的角度来看,他们也可能成为喜欢你的应用并推荐给其他人的用户。对于那些使用广告拦截技术的用户,一个更温和的方法是显示你自己的“内部”广告。创建一个或多个横幅图片,并在与普通广告相同的位置显示它们,使用相同高度的 ImageView(例如 50dp)。如果成功接收到广告,则将 ImageView 的可见性设置为 View.GONE。你甚至可以创建一个计时器来循环播放几个内部广告,以吸引用户注意。点击你的广告可以带用户进入市场页面购买完整版。

我正在展示一个比普通广告视图更大的块,附带一段文字解释为什么我必须展示广告。服务器成本等等。我从你那里得到了基本的想法,所以谢谢! - EvanBlack
3
我怀疑使用广告拦截器的人不是那种会购买你的应用程序的人,他们想要一切免费的。 - tsukimi

5

你能检查一下广告是否已经在你的应用程序中加载了吗?

广告拦截器的作用是防止你的应用程序下载数据。你可以检查广告框架中数据的内容长度,以确保数据存在。

如果没有数据,请弹出一条消息并退出,或通过电子邮件警告你。

这可能不是你想象中的那么大的问题,因为只有很少一部分人会屏蔽广告。


1
内容拦截器可以向您的应用程序“提供”长时间的空白页面,而不是广告。 - Borealid
似乎广告拦截器会阻止向已知广告服务器的HTTP请求。我们能否检查请求是否被发送?这似乎与无填充情况不同。 - Christopher Perry
@Scienceprodigy 是的。您可以对广告服务器执行头请求并检查响应标头。如果请求未被阻止,则知道存在与广告的连接。这可能有助于解决填充率问题。 - Byron Whitlock

4
前两个答案仅帮助您使用特定的广告拦截方法(可能是最流行的)。Root用户还可以通过设备上的防火墙来拦截广告。WiFi用户可以使用上游防火墙来拦截广告。
我建议:
1. 不要奖励使用广告拦截的用户。即使无法加载广告,请确保您的布局为广告保留一部分显示区域。或者,如果您有一个全屏广告播放一会儿,请确保您的应用程序等待片刻,即使广告不能播放。如果您将通知用作广告(你这个人渣),请在未能获取此类广告时通知用户。这可能被解读为“惹恼所有用户”,但您的普通用户知道他们正在得到什么,而您不需要广告拦截的“用户”。 2. 请求广告拦截器停止使用。供应用户所需内容的行业越不盈利,该行业提供给用户所需内容的数量就越少。单个开发人员将发现,为其他用户提供服务可以赚取更多的钱。您知道这一点,告诉用户后,他们会认为这很明显,但这仍然是一个经济论点-它并不直观。备用广告可以说:“这是我的工作。如果您不付费,我会找到另一个工作,您将无法从我这里获得更多此类应用程序。”

2
经历了放手的过程,试图不那么担心,并最终采取行动后,我的经验告诉我,这些用户对你的工作毫不在乎。在我的情况下,他们正是那些长期免费使用应用程序的人,从未花时间撰写积极的评论,但在我实施广告屏蔽器后突然发布了1星评级。没有社会工程学或同理心能说服他们,你的时间和技术知识是要花钱的(对他们来说只是零头)。依我拙见,他们只是搭便车者而已。就这样吧。 - davidcesarino

3
与其检查已安装或修改的单个软件主机文件,我的方法是使用类似于这样的AdListener,如果广告由于NETWORK_ERROR而无法加载,我只需获取一些随机的始终在线的页面(比如apple.com)并检查页面是否成功加载。

如果成功,应用程序就可以开始了

为了添加一些代码,监听器类应该是这样的:

public abstract class AdBlockerListener implements AdListener {

    @Override
    public void onFailedToReceiveAd(Ad arg0, ErrorCode arg1) {
        if (arg1.equals(ErrorCode.NETWORK_ERROR)) {
            try {
                URL url = new URL("http://www.apple.com/");
                URLConnection conn = url.openConnection();
                BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                reader.readLine();
                onAdBlocked();
            } catch (IOException e) {}
        }
    }

    public abstract void onAdBlocked();
}

然后,每个带有adView的活动都会执行以下操作:

AdView adView = (AdView) findViewById(R.id.adView);
        adView.setAdListener(new AdBlockerListener() {
            @Override
            public void onAdBlocked() {
                AlertDialog ad = new AlertDialog.Builder(CalendarView.this)
                                    .setMessage("nono")
                                    .setCancelable(false)
                                    .setNegativeButton("OK", new OnClickListener() {
                                        public void onClick(DialogInterface dialog, int which) {
                                            System.exit(1);
                                        }
                                    })
                                    .show();
            }
        });

2
这种方法的问题在于它可能会因广告网络错误或不稳定的互联网连接而导致误报警,从而轻易地打扰到合法用户。它过于激进了。 - Ahmet Noyan Kızıltan
此外,AdBlockerListener的实现与AdListener的最新更改不匹配。这段代码会抛出多个错误。 - CanCoder

3

你做的任何事情,你的用户都可以做得更好。

唯一能够在某种程度上有效的方法是将广告作为程序的不可分割部分,这样如果广告被屏蔽,用户就无法理解/与应用程序进行交互。


有没有办法检测广告是否被屏蔽了? - Christopher Perry
2
不管你做什么,广告拦截器都可能变得更加复杂。这是一场猫捉老鼠的游戏,而他们占据了优势。 - Borealid
1
嗯,我们可以开发一个检测广告拦截程序的反广告拦截器。我们可以将其开源,这样所有知道广告拦截程序的人都可以将其添加到列表中。 - Christopher Perry
当广告拦截器伪装成一个商业成功的应用程序名称时,会发生什么? - Borealid
2
它怎么做到的?你无法实时更改已安装应用程序的包名称。 - Christopher Perry

1

用户绕过广告有两种方法:

1)在没有联网的情况下使用应用程序。

2)使用已 root 的手机和修改后的主机文件。

我制作了两个工具,您可以实现,请参见以下代码。

checkifonline(); 用于解决问题1:

public void checkifonline() {
    boolean haveConnectedWifi = false;
    boolean haveConnectedMobile = false;

    ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo[] netInfo = cm.getAllNetworkInfo();
    for (NetworkInfo ni : netInfo) {
        if (ni.getTypeName().equalsIgnoreCase("WIFI"))
            if (ni.isConnected())
                haveConnectedWifi = true;
        if (ni.getTypeName().equalsIgnoreCase("MOBILE"))
            if (ni.isConnected())
                haveConnectedMobile = true;
    }

    if(haveConnectedWifi==false && haveConnectedMobile==false){

        // TODO (could make massage and than finish();
    }
}

adblockcheck();是针对问题2的

private void adblockcheck() {
    BufferedReader in = null;
    boolean result = true;

    try 
    {
        in = new BufferedReader(new InputStreamReader(
                new FileInputStream("/etc/hosts")));
        String line;

        while ((line = in.readLine()) != null)
        {
            if (line.contains("admob"))
            {
                result = false;
                break;
            }
        }
    } catch (UnknownHostException e) { }
      catch (IOException e) {e.printStackTrace();}  

    if(result==false){

        // TODO (could make massage and than finish();

    }
}

我对于一个不需要互联网却仍然要求连接网络的应用程序,第一件事就是将这个臭烘烘的垃圾从我的设备中扔掉。 - Oleg V. Volkov
也许你想获取分析数据以便改进,或者展示广告以购买三明治和啤酒,因为没有三明治和啤酒,程序员是无法编程的。 - John

1

我认为这取决于广告内容提供商。我知道AdMob SDK在广告请求失败时提供回调。我猜想你可以注册这个回调,然后在回调中检查连接 - 如果有连接而你没有收到广告 - 注意一下,如果发生了一两次以上的情况,很可能你的广告被阻止了。我没有使用过Google的AdSense for Mobile工具集,但如果有类似的回调机制,我也不会感到惊讶。


我已经在另一个使用Quattro支持AdMob的应用程序上实现了这一点,因为Quattro的填充率很低。当Quattro无法提供广告时,我会提供一个AdMob广告。但是,我如何知道这是由于广告拦截还是填充率不良引起的呢? - Christopher Perry
1
似乎没有办法在不采用其他手段(例如检查已知的广告拦截应用程序)的情况下区分未填充和被阻止的广告。 - nEx.Software

0
首先,我想说的是,我认为在应用程序中使用广告拦截实际上是一种盗版行为。这些应用程序是通过广告支持的,有时还需要“付费许可证”才能关闭广告和/或添加功能。通过拦截广告,用户会从开发人员那里窃取潜在的收入,而这些开发人员花费了时间来创建您正在使用的应用程序。
无论如何,我想添加一种方法来帮助防止使用广告拦截器。我使用这种方法,如果检测到广告拦截器,我不允许用户使用该应用程序。人们会非常生气,并给你差评。但是,我在我的应用程序描述中非常清楚地说明,如果您使用广告拦截器,则无法使用该应用程序。
我使用软件包管理器来检查是否安装了特定软件包。虽然这不能获取所有广告拦截器,但如果您保持对一些流行的广告拦截器“最新”,则可以获得大部分广告拦截器。
PackageManager pm = activity.getPackageManager ();
Intent intent = pm.getLaunchIntentForPackage ( "de.ub0r.android.adBlock" );
if ( Reflection.isPackageInstalled ( activity, intent ) ) {
  // they have adblock installed
}

1
请注意,这只处理一个测试用例。今天有许多应用程序可以阻止广告 :( - Jared Burrows
1
以上示例只处理了一种情况。我是在回答问题,而不是提供所有广告拦截软件包的列表。我的实际解决方案比一个软件包名称要多得多。我的示例还没有向你展示“isPackageInstalled”的代码。它并不是为生产代码提供的,而是作为可以完成和开始自己的解决方案的东西。 - Ryan Conrad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接