広告ブロックアプリ「Crystal」で動作しないアナリティクスを動かす方法

iPhoneの人気有料広告ブロックアプリ「Crystal」が、Googleアナリティクスまで無効化するらしい。

[【検証2】iOS 9の広告ブロックがGAを無効化！の件を、広告屋として調べてみた（+Optmizely）【150923更新】 - でぶててのWEB録](http://tetesuke.hatenadiary.jp/entry/ads_block_ios9_ga)

#実際に検証してみる
|Crystal|1Blocker|AdBlock Plus|
|:-----------:|:------------:|:------------:|
|動作しない|問題なく動作|問題なく動作|

実際にiOS 9にアップデートし、人気どころの3つのアプリで検証。Googleアナリティクスのリアルタイムレポートを用いて調べると、**「Crystal」では確かにGoogleアナリティクスが動作しない**ことが分かる。アクセス解析に不都合が生じるので、今回はこれを動くように試みる。

#アナリティクスがブロックされている場合のみ「Measurement Protocol」を叩く

「Measurement Protocol」はユニバーサルアナリティクスより追加された新機能で、画像ビーコンにより直接情報が送信できる仕組みです。手順としては、
1. アナリティクスが効いているか調べる
2. 効いていない場合にのみ「Measurement Protocol」発動
と言った感じでできそうです。

アナリティクスが効くかどうかは、下記の記事を読むに、結構簡単に調べることが可能なようです。

[[iOS9] コンテンツブロックされているかどうかチェックする方法 | SEM Technology](https://sem-technology.info/sem-tools/check-contents-block)

サンプルを示します。通常のユニバーサルアナリティクスが&lt;body&gt;直後に設置されているものとします。そして、&lt;/body&gt;直前にcheck.jsを読み込ませます。

````html:test.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Test page</title>
<meta charset="utf-8">
</head>
<body>
<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-XXXXXXXX-X', 'auto');
  ga('send', 'pageview');

</script>
<!-- Contents -->
<script src="check.js"></script>
</body>
</html>
````
「check.js」は
・アナリティクスが効いていない時に
・JavaScriptで取れるユーザー情報を「ga.php」にパラメータ付加して画像として設置
させており、内容は下記の通りです。

````js:check.js
if (typeof(window[window['GoogleAnalyticsObject']].getByName) === 'undefined') {
	(function(d, s) {
		var f = d.getElementsByTagName(s)[0],
			i = d.createElement('img'),
			dl = document.location.origin + document.location.pathname + document.location.search,
			dt = d.title,
			sr = screen.width + 'x' + screen.height,
			vp = screen.availWidth + 'x' + screen.availHeight,
			sd = screen.colorDepth;
		i.src = "ga.php?dl=" + encodeURIComponent(dl) + "&dt=" + encodeURIComponent(dt) + "&sr=" + sr + "&vp=" + vp + "&sd=" + sd;
		f.parentNode.insertBefore(i, f);
	})(document, 'script');
}
```
次に実際に「Measurement Protocol」を作成している「ga.php」です。
JavaScriptで取れる（取りやすい）情報は「check.js」内で取得しておいて、「ga.php」にGETで送っておき、PHPで取得できる情報を足した上で「Measurement Protocol」を作成しています。
出来たURLをfile_get_contentsにて叩いたのち、1px×1pxの透過GIF画像を出力しています。

````php:ga.php
<?php
	$cid = "";

	// クライアントIDのCookieがある場合利用
	if(isset($_COOKIE["measurementprotocol"]) && strlen($_COOKIE["measurementprotocol"]) == 36) $cid = $_COOKIE["measurementprotocol"];

	// 無い場合生成
	else $cid = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff));

	// プロトコルのバージョン（必須）
	$param = "?v=1";

	// トラッキングID（必須）
	$param .= "&tid=UA-XXXXXXXX-X";

	// クライアントID（必須）
	$param .= "&cid=".$cid;

	// IP オーバーライド（任意）
	$param .= "&uip=".$_SERVER['REMOTE_ADDR'];

	// ユーザー エージェント オーバーライド（任意）
	$param .= "&ua=".rawurlencode($_SERVER['HTTP_USER_AGENT']);

	// 画面の解像度（任意）
	$param .= isset($_GET['sr']) && is_string($_GET['sr']) ? "&sr=".$_GET['sr'] : '';

	// 表示領域のサイズ（任意）
	$param .= isset($_GET['vp']) && is_string($_GET['vp']) ? "&vp=".$_GET['vp'] : '';

	// ドキュメントのエンコード（任意）
	$param .= "&de=UTF-8";

	// 画面の色（任意）
	$param .= isset($_GET['sd']) && is_string($_GET['sd']) ? "&sd=".$_GET['sd']."-bit" : '';

	// ユーザーの言語（任意）
	$param .= "&ul=ja";

	// ヒットタイプ（必須）
	$param .= "&t=pageview";

	// ドキュメントの場所のURL（任意）
	$param .= isset($_GET['dl']) && is_string($_GET['dl']) ? "&dl=".$_GET['dl']."[Blocked]" : '';

	// ドキュメント タイトル（任意）
	$param .= isset($_GET['dt']) && is_string($_GET['dt']) ? "&dt=[Blocked]".$_GET['dt'] : '';

	// キャッシュの無効化（任意）
	$param .= "&z=".mt_rand(100000000000, 199999999999);

	// Measurement Protocol叩く
	file_get_contents("https://ssl.google-analytics.com/collect".$param);

	// 画像ヘッダ出力
	header("Content-type: image/gif");

	// Cookieの保存（アナリティクス同様、とりあえず2年とする）
	setcookie("measurementprotocol", $cid, time() + (3600 * 24 * 365 * 2));

	// 1px×1pxの透過GIF画像を表示
	echo base64_decode("R0lGODlhAQABAID/AP///wAAACwAAAAAAQABAAACAkQBADs=");
?>
```
「cid（クライアントID）」の生成箇所は、下記参考リンクより頂戴しています。
[Google Analytics Measurement Protocol for PHP - Campaign Tracking - Mudd Advertising]
(http://mudd.com/blog/google-analytics-measurement-protocol-for-php-campaign-tracking/)

今回の例ではブロックされていることを分かりやすくするため、下記のように[Blocked]を足した状態でデータを取れるようにしております。必要なければ削除しても構いません。

|ページタイトル|仮想ページビュー|
|:-----------:|:------------:|
|【Blocked】ページのタイトル|/test/【Blocked】|

ちなみに

````html
<img src="ga.php?dl=%2Ftest%2F&dt=TEST" alt="">
```
などとすることで、ガラケーなどでもユニバーサルアナリティクスにデータ送信することが可能です。パラメータ「dl」は「ドキュメントの場所のURL」、「dt」は「ドキュメント タイトル」を示しますが、UTF-8にてURLエンコードした上で付加して下さい。

なお、「Measurement Protocol」のパラメータについては公式ページにて詳しく説明されています。

[Measurement Protocol のパラメータ リファレンス  |  アナリティクス Measurement Protocol  |  Google Developers]
(https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters?hl=ja)