Web解析」カテゴリーアーカイブ

PhonegapアプリにAdobe Mobile SDKを入れる

まずはMac上でPhonegapアプリを作るところから始めた。

ググると結構古い情報がヒットして困ったが、Phongegapの中身はCordovaなので、Cordovaの環境を揃えれば良いそうだ。

Xcodeはインストール済みだったので、
Xcodeコマンドラインツールを入れる。

あと、gitもインストール済みなので、そのまま使う。

で、今度はNode.jsを入れる。
node.jsに含まれるnpmコマンドを使うためである。
https://nodejs.org/en/

そしてcordovaをインストールする

$ sudo npm install cordova -g

インストールしたら、早速テストプロジェクトを作る

$ cordova create test-project

そしてiOSとAndroidのプラットフォームを追加

$ cordova platforms add ios
$ cordova platforms add android

そうするとtest-project/platforms配下にiosとandroidというディレクトリがそれぞれ出来上がるので、それらをbuildしたのち、エミュレーターで起動できます。

$ cordova build ios
$ cordova emulate ios

というわけで、次はAdobeのSDKを入れます。
管理画面からPhonegap pluginというのもダウンロードしておきます。
https://marketing.adobe.com/resources/help/en_US/mobile/ios/phonegap.html
最初はiOS。通常のiOSアプリと同じくADBMobileライブラリとADBMobileConfig.jsonをプロジェクトに追加します。

そして、ADBMobile_PhoneGap.h と ADBMobile_PhoneGap.m プロジェクトのpluginsフォルダにコピー。

それから、test-project/platforms/ios/www にPhonegapプラグインに含まれるADBHelpler.jsをコピーする。

で、config.xmlに下記の要素を貼り付けるとあるが、config.xmlがプロジェクトのrootとplatforms/ios/の2箇所にあるんだが、どっちだ?
とりあえず両方に入れといたw

<feature name="ADBMobile_PhoneGap">
    <param name="ios-package" value="ADBMobile_PhoneGap" />
</feature>

ここまでやったら、次はADBHelper.jsの実装。
とりあえずwwwの中のindex.htmlに入れる。
閉じタグの直前に、ADBHelper.jsをインクルード。

<script type="text/javascript" charset="utf-8" src="ADB_Helper.js"></script>

あとは各ADB.trackStateをコールすればビーコンが飛ぶ、はずなのですが、どうやらCordovaアプリ内ではonDeviceReadyイベントが発生してからじゃないと制御出来ない。

で、とりあえずjs/index.js内でonDeviceReadyで実行されるコールバック関数があったので、その中にADB.trackStateを入れたら動いた

    onDeviceReady: function() {
        app.receivedEvent('deviceready');
    },
    // Update DOM on a Received Event
    receivedEvent: function(id) {
        var parentElement = document.getElementById(id);
        var listeningElement = parentElement.querySelector('.listening');
        var receivedElement = parentElement.querySelector('.received');

        listeningElement.setAttribute('style', 'display:none;');
        receivedElement.setAttribute('style', 'display:block;');

        console.log('Received Event: ' + id);
        
        /* ここでAdobe Analyticsのコードを実行 */
        ADB.setDebugLogging(true);
        ADB.collectLifecycleData();
        //pageNameにHelloCordova、prop1にhogeをセット
        ADB.trackState("HelloCordova", {"&&c1":"hoge"}); 
    }

trackingServerへの送信ビーコンの中身はXcodeのコンソールに出てくるので、それで確認。
Phonegapプラグインがちゃんとpluginsフォルダにコピーされてないとプラグインが見つからないというエラーが出てきて怒られるので注意。

以上iOS

Androidも大体やる事は同じ。
https://marketing.adobe.com/resources/help/en_US/mobile/android/phonegap.html
しかしbuildしたらtargetが見つからないとかで怒られる。

$ cordova build android

というわけでAndroid SDK Managerを起動してもろもろバージョンアップしたりインストールしてretryしたら動いた。

Firebaseを試す (Android)

Firebase の Android 版も試しました。

ここらへんを参考
https://firebase.google.com/docs/analytics/android/start/
http://dev.classmethod.jp/smartphone/firebase-analytics-getting-started/

で、導入するためにまず Android Studio を 2.2 Preview にバージョンアップ。
2.2 以降じゃないと諸々不具合があるらしく、実は最初ハマった。。
あと、情報収集のために「firebase android」あたりのワードでぐぐると、古い情報がやたらヒットして困るので、Google Firebaseの公式docを読むのが吉。

iOS と違ってとくにビルド時の問題はなし。
で、肝心のFirebase Analyticsの分析機能はGoogle Analyticsのサブセットみたいなもんだった。
Firebaseはやはりプラットフォームであって、Analyticsはおまけ。

Firebase を試す (iOS)

さっそく無償で使える Firebase を試しました。

Firebase を Xcode で使うには cocoapods が必要。
という訳で、まずはググって見つけた手順に沿って cocoapods を入れる。

ここらへんとか参考。
https://www.firebase.com/docs/ios/guide/setup.html
https://cocoapods.org/pods/Firebase

あとは、Firebase にプロジェクトを作って進めていく。

ここらへんを参考。
http://dev.classmethod.jp/smartphone/firebase-notification-ios/

そして手元の iOS アプリに組み込んでみたところ、 Build Failed…

framework not found Pods
error: linker command failed with exit code 1 (use -v to see invocation)

というメッセージが出てきてシミュレータが起動しない。

で、Framework フォルダの下にある Pods.framework が赤文字で表示されていて、どうやらこのファイルが存在しない模様。
そして解決策は、この Framework/Pods.framework を Xcode から削除すればOK。
Stackoverflowにも似たような投稿あり

動いた。
Firebase Analytics にデータが入り始めたので、他にも色々機能を使ってみる。

[Adobe Analytics] Legacy s_code.js から AppMeasurement.js に乗り換える

もろもろ新機能を試したいので、s_code.js から AppMeasurement.js に乗り換えました。

やった事:

ファイル名は s_code.js のままで、 “DO NOT ALTER BELOW THIS LINE” のコメント行配下の本体を、 AppMeasurement.js の本体に貼りかえるというのが基本。

あと、 Media モジュールで動画計測してるので、モジュールを AppMeasurement_Module_Media.js + AppMeasurement_Module_Integrate.js の内容に貼りかえる。

次にプラグインの互換性についてはここで調べる。
https://marketing.adobe.com/resources/help/ja_JP/sc/implement/plugins_support.html
お、 getPageName プラグイン動くじゃーん、と思ってそのまま試したら s.wd がないとか s.fl がないなどエラーが出てきて怒られるので、下記のように一部を変更。

  • s.wd.location を location.href に置き換える
  • s_code.js から s.fl と s.pt を持って来る。

で、出来上がった getPageName プラグインがこれ。

/*
 * Plugin: getPageName v2.1 - for AppMeasurement.js
 */
s.getPageName=new Function("u",""
+"var s=this,v=u?u:''+location.href,x=v.indexOf(':'),y=v.indexOf('/',"
+"x+4),z=v.indexOf('?'),c=s.pathConcatDelim,e=s.pathExcludeDelim,g=s."
+"queryVarsList,d=s.siteID,n=d?d:'',q=z<0?'':v.substring(z+1),p=v.sub"
+"string(y+1,q?z:v.length);z=p.indexOf('#');p=z<0?p:s.fl(p,z);x=e?p.i"
+"ndexOf(e):-1;p=x<0?p:s.fl(p,x);p+=!p||p.charAt(p.length-1)=='/'?s.d"
+"efaultPage:'';y=c?c:'/';while(p){x=p.indexOf('/');x=x<0?p.length:x;"
+"z=s.fl(p,x);if(!s.pt(s.pathExcludeList,',','p_c',z))n+=n?y+z:z;p=p."
+"substring(x+1)}y=c?c:'?';while(g){x=g.indexOf(',');x=x<0?g.length:x"
+";z=s.fl(g,x);z=s.pt(q,'&','p_c',z);if(z){n+=n?y+z:z;y=c?c:'&'}g=g.s"
+"ubstring(x+1)}return n");
s.fl=function(x,l){return x?(''+x).substring(0,l):x};
s.pt=function(x,d,f,a){var s=this,t=x,z=0,y,r;while(t){y=t.indexOf(d);
y=y<0?t.length:y;t=t.substring(0,y);r=s[f](t,a);if(r)return r;
z+=y+d.length;t=x.substring(z,x.length);t=z<x.length?t:''}return ''};

あと、 s.getQueryParam じゃなくて、 s.Util.getQueryParam を使ってね、とヘルプに書いてあるので、 s.Util.getQueryParam を旧 s.getQueryParam にコピー

/*
 * Plugin: getQueryParam
 */
s.getQueryParam = s.Util.getQueryParam;

あちこち実装済みの s.getQueryParam をイチイチ s.Util.getQueryParam に書き換える必要はない。
※/* 20160831追記*/
このままだと第2・第3引数が正常に動作しないので、実はもうちょい工夫が要ります。
さらに、従来のs.getQueryParamのように、複数の引数をカンマ区切りで同時にセットする事も出来ません。
そこらへんも直す必要があります。
getQueryParam versus Util.getQueryParam

s.c_r と s.c_w は いまのところAppMeasurement でも動くので、そのままにしておく。

いまだに Target Classic 使ってるところは s.trackTNT プラグインを使う事もあるだろうけど、これも s.wd が見つからないというエラーが出るので、 s.wd を window に置換すれば良し。

とりあえず、プラグイン類は、 FormAnalysis 以外はちょいちょい弄れば AppMeasurement でも動きそうね。
FormAnalysis は DTM のイベントルール設定で似たような実装をする事も可能だろうけど、面倒だから今のところはスルー。

Google Tag Manager移行後もハードコードのイベントトラッキングを実行する

GTMに移行後、ページに直接onclick記述してるGAのイベントトラッキングが動かないと思ったら、「トラッカー名を設定する」のチェックが必要だった。

[タグを設定] > [高度な設定] > [トラッカー名を設定する] にチェックを入れるだけ。
[トラッカー名]のフィールドは空白のままでOK。

gtm

Facebookのいいねボタンや、Twitterのツイートボタンのクリックを計測する

5年前とはSDKの仕様が変わってたので、改めてSiteCatalystとGoogleAnalyticsを実装してみた。
こちらのページでテストしました。
http://www.kwonline.org/tst/social.php
下記の4つのボタンのクリックを計測してます。

  • Facebook
  • Twitter
  • はてなブックマーク
  • LINE

Facebook
Facebookは以前のall.jsじゃなくて、sdk.jsになってます。
FB.Event.subscribe関数を使う点はsdk.jsでも変わってません。

window.fbAsyncInit = function(){
	//sitecatalyst
	FB.Event.subscribe("edge.create", function(){
		s.linkTrackVars = "events,eVar1";
		s.linkTrackEvents = s.events = "event3";
		s.eVar1 = "facebook";
		s.tl(true, "o", "facebook");
		//google analytics
		ga('send', 'social', 'facebook', 'like', location.href);
	});
};

Twitter
Twitterは通常のボタン設置方法じゃなくて、developerサイトに載ってるscriptに変える必要があります。
https://dev.twitter.com/web/javascript/loading

window.twttr = (function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0],
    t = window.twttr || {};
  if (d.getElementById(id)) return t;
  js = d.createElement(s);
  js.id = id;
  js.src = "https://platform.twitter.com/widgets.js";
  fjs.parentNode.insertBefore(js, fjs);
  t._e = [];
  t.ready = function(f) {
    t._e.push(f);
  };
  return t;
}(document, "script", "twitter-wjs"));

上記のスクリプトに変えた上で、下記のようにclickイベントにバインドします。

twttr.ready(function (twttr) {
	twttr.events.bind("click", function (){
		//sitecatalyst
		s.linkTrackVars = "events,eVar1";
		s.linkTrackEvents = s.events = "event3";
		s.eVar1 = "twitter";
		s.tl(true, "o", "twitter");
		//google analytics
		ga('send', 'social', 'twitter', 'click', location.href);
	});
});

はてなブックマーク & LINE
「はてなブックマーク」と、「LINEに送る」ボタンはコールバック関数がないので、
勝手にclass属性をつけて、JQueryでclickイベントにバインドするという、実装にしました。
もっとスマートなやり方はあるんだろうか。

[Adobe Analytics] ADBMobileSample-1.1-Android で java.lang.IllegalArgumentException: provider=network エラー

Adobe Mobile SDKのAndroidサンプルアプリをAndroidエミュレーターで起動しようとすると、java.lang.IllegalArgumentException: provider=network というエラーが出てアプリが起動しませんでした。

どうやらエミュレーターではLocationManager.NETWORK_PROVIDERが使えないのですかね?
対策として、LocationManager.NETWORK_PROVIDERが使えない場合は使わない、という元も子もない対策でしのいでます。

MenuActivity.java の 137行目

locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);

これが問題なので、下記のようにif文で囲ったらサンプルアプリが起動しました。

if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
  locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
}

参考したサイトは毎度おなじみStack Overflow
Caused by: java.lang.IllegalArgumentException: provider=network

[Adobe Analytics] HTML5動画計測

SiteCatalystの頃から使われている動画計測手法、Milestone型計測を使って、HTML5動画計測を実装したサンプルコードを載せておきます。
Video Tracking Test

ちなみに上記テストページに載せている動画はオープンソースの3DCGソフトウェアBlenderで作成された「Big Buck Bunny」というムービーです。
Big Buck Bunny – Wikipedia, the free encyclopedia

実装したコード:

s.loadModule("Media");
s.Media.trackWhilePlaying = true;
s.Media.segmentByMilestones = true;
s.Media.playerName = "My_HTML5_Player";
s.Media.trackVars="events,eVar11,eVar12";
s.Media.trackEvents="event11,event12,event13";
s.Media.trackMilestones = "25,50,75";
s.Media.trackUsingContextData = true;
s.Media.contextDataMapping = {
	"a.media.name" : "eVar11",
	"a.contentType" : "eVar12",
	"a.media.timePlayed" : "event11",
	"a.media.view" : "event12",
	"a.media.complete" : "event13"
};

function playerHandler(e){
    if (myvideo.currentTime > 0) {
        currentTime = myvideo.currentTime;
    }
    switch(e.type){
        case "play":
            if(!videoOpened){
                s.Media.open(myvideo.src, myvideo.duration, s.Media.playerName);
                s.Media.play(myvideo.src, 0);
            }else{
                s.Media.play(myvideo.src, currentTime);
            }
            videoOpened = true;
	    break;
        case "pause":
            s.Media.stop(myvideo.src, currentTime);
	    break;
        case "ended":
            s.Media.stop(myvideo.src, currentTime);
            s.Media.close(myvideo.src);
	    break;
        default:
	    break;
    }
}

if (document.getElementById("myvideo")) {
	var videoOpened = false;
	var currentTime = 0;
	var myvideo = document.getElementById("myvideo");
	myvideo.addEventListener("loadedmetadata",playerHandler,false);
	myvideo.addEventListener("play",playerHandler,false);
	myvideo.addEventListener("pause",playerHandler,false);
	myvideo.addEventListener("ended",playerHandler,false);
}

新しい計測手法のHeartbeat型計測は別の機会にやってみます。

ドメインを統一

このサイトのURLはwww.kwonline.orgですが、以前はサブドメインなしのkwonline.orgでもアクセス出来ました。

しかし、同じページにURLが二つもあると、Web解析的にもやりづらいのと、検索エンジンに両方のURLがインデックスされてしまいます。
そこで、URLをwww.kwonline.orgで統一する事にしました。

Apacheの.htaccessを使うやり方です。
ルートディレクトリに、下記のような.htaccessファイルを置いてあります。

.htaccess

RewriteEngine On

# Force redirect to www
RewriteCond %{HTTP_HOST} ^kwonline\.org
RewriteRule ^(.*) http://www.kwonline.org/$1 [R=301,L]

この記述により、サブドメなしのkwonline.orgにアクセスしても、強制的にwww.kwonline.orgに301リダイレクトされます。

[Adobe Analytics] Mobile SDK 4.x でアプリ計測する際の小技

久々にスマホアプリをSiteCatalystで計測する方法について調べる機会がありました。

現在リリースされているアプリ計測ライブラリだと、昔のような

s.pageName = "top";
s.prop1 = "main";
s.eVar1 = "man";
s.events = "event1";
s.track();

みたいな実装をしないんですね。

Context Data and Adobe Mobile Analytics: Change is Good

で、代わりにContext Dataに入れた値をProcessing Rule (処理ルール)で変数に入れるという。

HashMap cdata = new HashMap<String, Object>();
cdata.put("my.section", "main");
cdata.put("my.gender", "man");
cdata.put("my.action", "login");
Analytics.trackState("top", cdata);

みたいに実装して、Processing RulesでContext Dataからそれぞれ任意の変数に値をコピーする、と。
この方がより直感的だ、と言われてるそうですが、昔ながらのSiteCatalystのインプリに慣れてるので、かえって心地悪い。
あと、Processing RuleだとビーコンをCharlesやBloodhoundで見て目視、という確認がやりづらい。

従来のs変数に直接値を入れるやり方がもう出来ないのか?という訳でもありませんでした。
Processing Rulesがサポートしていないproducts変数や、events変数のシリアライゼーションは”&&”を付けて直接値を代入するやり方です。

Products Variable – Android SDK 4.x for Marketing Cloud Solutions

cdata.put("&&products", "Category;Product;Quantity;Price");

見慣れたproducts変数の構文です。

Event Serialization – Android SDK 4.x for Marketing Cloud Solutions

cdata.put("&&events", "event1:12341234");

実際に使った事はないんですが、お馴染みのイベントシリアライゼーションの書き方です。

というわけでビーコンパラメータ名(変数名ではない)に、”&&”を付けることで、Context Dataではなく、通常のパラメータとして処理されるようです。
パラメータ名だとこうなります。

  • prop1 → c1
  • eVar1 → v1
HashMap cdata = new HashMap<String, Object>();
cdata.put("&&c1", "main");
cdata.put("&&v1", "man");
cdata.put("&&events", "event1");
Analytics.trackState("top", cdata);

pageNameはtrackStateの第一引数なので仕方ない。
で、ビーコンをログで見るとちゃんとパラメータに入ってますね。
log
&c. から &.c の間に入るとContext Data扱いになり、Context DataはProcessing Rulesで拾わない限りレポートには出てきません。
で、”&&パラメータ名”という書式でセットすれば、&c. ~ &.c の外につくので、Context Dataにならない。
そのため、Processing Rulesを使わなくても、直接値をセット出来る、という仕組みです。

この”&&パラメータ名”の仕組みを使って直接値をセットすれば、”D=”のDynamic Variablesも使えるので

cdata.put("&&c1", "foobar");
cdata.put("&&v1", "D=c1");

という書式でprop1の値をeVar1にコピーする、おなじみのインプリも可能です。

events変数に数値を入れるカウンタ型を使う時も

cdata.put("&&events", "event2=5");

この書き方で対応します。