2021年8月25日 星期三

AppsFlyer 廣告追蹤

 Apps Flyer 是一個多平台整合的廣告追蹤網站


Apps Flyer 相關

Android SDK 集成

iOS SDK 集成


Facebook 相關

Facebook 廣告配置指南

Facebook SDK

Facebook Dashboard



iOS 14.5 官方將廣告追蹤透明化

必須經過用戶同意方可進行追蹤

再設定 Facebook 追蹤時,

必須將事件管理工具 > 資料來源 > 設定 > 為 SKAdNetwork 設定應用程式事件 開啟

並編輯事件,才可以收到來自 iOS 的資料


Swift 

AppEvents.logEvent(AppEvents.Name.completedRegistration)


2021年8月24日 星期二

iOS 訂閱性商品是否可取得續訂資料

 可以透過 iOS 驗證收據中,取得最新的訂閱資料中查看 訂閱截止日

作法:

  1. iOS成功購買產品後,呼叫 Fetch the Receipt Data(備註1) 去取 Apple Store 收據
  2. 因為 Apple Store 收據 本身有經過加密,也因為安全性的問題,需由後端去與 Apple 伺服器溝通
  3. 承第二點可透過 POST MAN 進行測試實際用法參考 (備註2)
  4. 將第一點取得的加密字串傳給後端API
  5. 由後端去和APPLE伺服器溝通,取得解碼後的收據詳細資料(JSONObject)
  6. 儲存至DB

備註:
1. iOS 原生

if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL, FileManager,default.fileExists(atPath: appStoreReceiptURL.path){
  do{
    let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped)
    let receiptString = receiptData.base64EncodedString(options: [])

    // 呼叫 API

  } catch {
    print("Couldn't read receipt data with error: " + error.localizedDescription)
  }
}

2. 驗證收據是否正確
正式驗證 API 網址
https://buy.itunes.apple.com/verifyReceipt
沙箱驗證 API 網址
https://sandbox.itunes.apple.com/verifyReceipt
資料來源:https://www.jianshu.com/p/d0ac8cec794b

3. 驗證資料的格式,必須自建為 JSONObject
https://developer.apple.com/documentation/appstorereceipts/requestbody

4.回傳的狀態碼
https://developer.apple.com/documentation/appstorereceipts/status

5. 後端

function setReceiptIos($arr){
		if(!isset($arr)){
			return 'ESY9001';
		} else if(empty($arr["receipt_data"])){
			return 'EPT0015';
		} else if(empty($arr["uid"])){
			return 'EPT0007';
		} else if(empty($arr["iap_type"])){
			return 'EPT0016';
		} else if(empty($arr["ptid"])){
			return 'EPT0004';
		}
		
		// get mydb
		$mydb = &$this->mydb;
		
		date_default_timezone_set("Asia/Taipei");
		
		function acurl($receipt_data, $sandbox=0){
			
			// SandBox , Official
			$secret = apple_connect_serect_key;
			$POSTFIELDS = array("receipt-data" => $receipt_data, 'password'=>$secret, "");
			$POSTFIELDS = json_encode($POSTFIELDS);
	 
			//正式購買地址 沙盒購買地址
			$url_buy     = "https://buy.itunes.apple.com/verifyReceipt";
			$url_sandbox = "https://sandbox.itunes.apple.com/verifyReceipt";
			$url = $sandbox ? $url_sandbox : $url_buy;
	 
			//簡單的curl
			$ch = curl_init($url);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
			curl_setopt($ch, CURLOPT_POST, 1);
			curl_setopt($ch, CURLOPT_POSTFIELDS, $POSTFIELDS);
			$result = curl_exec($ch);
			curl_close($ch);
			return $result;
		}
		
		// 請求驗證
	    $html = acurl($arr["receipt_data"]);
		$data = json_decode($html, true);
		// 如果是沙盒資料 則驗證沙盒模式
	    if($data['status']=='21007'){
	        // 請求驗證
	        $html = acurl($arr["receipt_data"], 1);
	        $data = json_decode($html,true);
	        $data['sandbox'] = '1';
	    }
		
		 // 判斷是否購買成功
	    if(intval($data['status'])===0){
	        $result=array(
	            'status'  => $data['status'],
	            'message' => '購買成功'
	            );
	    }else{
			
	        $result=array(
	            'status'  => $data['status'],
	            'message' => '購買失敗'
	            );
				
			return $result;
	    }
		
		$latestPosition = 0;
		
		
		
		$purchase_date_ms = "0";
		
		$receipt = array();
		// latest_receipt_info 只會回傳可續訂的收據, 其他收據要在 IN_APP 裡面找
		if ($arr["iap_type"] == "subscription") {
			$receipt = $data["latest_receipt_info"];
		} 
		else {
			$receiptArr = $data["receipt"]["in_app"];
			$receiptArrLength = count($receiptArr);
			if ( $receiptArrLength > 0){
				for ($i=0; $i<$receiptArrLength; $i++){
					if ( (double) $receiptArr[$i]["purchase_date_ms"] > (double) $purchase_date_ms ){
						$purchase_date_ms = (double) $receiptArr[$i]["purchase_date_ms"]; 
						$latestPosition = $i;
					}
				}
			}
			
			$receipt = $receiptArr;
		}
		
		
		$transaction_id = 'NULL';
		if (isset($receipt[$latestPosition]["transaction_id"]) ){
			$transaction_id = "'".$receipt[$latestPosition]["transaction_id"]."'"; 
		}
		
		$product_id = 'NULL';
		if (isset($receipt[$latestPosition]["product_id"]) ){
			$product_id = "'".$receipt[$latestPosition]["product_id"]."'"; 
		}
		
		
		$purchase_date = 'NULL';
		if (isset($receipt[$latestPosition]["purchase_date"]) ){
			$purchase_date = "'".date("Y-m-d H:i:s",strtotime($receipt[$latestPosition]["purchase_date"]))."'"; 
		}
		
		$expires_date = 'NULL';
		if (isset($receipt[$latestPosition]["expires_date"]) ){
			$expires_date = "'".date("Y-m-d H:i:s",strtotime($receipt[$latestPosition]["expires_date"]))."'"; 
		}
		
		$cancellation_date = 'NULL';
		if (isset($receipt[$latestPosition]["cancellation_date"]) ){
			$cancellation_date = "'".date("Y-m-d H:i:s",strtotime($receipt[$latestPosition]["cancellation_date"]))."'"; 
		}
		
		$cancellation_reason = 'NULL';
		if (isset($receipt[$latestPosition]["cancellation_reason"]) ){
			$cancellation_reason = "'".$receipt[$latestPosition]["cancellation_reason"]."'"; 
		}
		
		$original_purchase_date = 'NULL';
		if (isset($receipt[$latestPosition]["original_purchase_date"]) ){
			$original_purchase_date = "'".date("Y-m-d H:i:s",strtotime($receipt[$latestPosition]["original_purchase_date"]))."'"; 
		}
		
		{ $query = "
		INSERT INTO `".PREFIX_TABLE_0."_".DB_NAME_1."`.`".PREFIX_TABLE_0."_history_user_ios_receipt` (
			`prefixid` ,
			`huirid` ,
			`uid` ,
			`transaction_id` ,
			`product_id` ,
			`purchase_date` ,
			`expires_date` ,
			`cancellation_date` ,
			`cancellation_reason` ,
			`original_purchase_date` ,
			`encode_string` ,
			`ptid` ,
			`seq` ,
			`switch` ,
			`insertt`,
			`modifyt`
		) VALUES (
			'".PREFIX_INDEX_0."',
			NULL,
			'".$arr["uid"]."',
			{$transaction_id},
			{$product_id},
			{$purchase_date},
			{$expires_date},
			{$cancellation_date},
			{$cancellation_reason},
			{$original_purchase_date},
			'".$arr["receipt_data"]."',
			'".$arr["ptid"]."',
			'10',
			'Y',
			NOW(),
			NOW()
		)";
		}
		
		
		// echo $query ; exit;
		if(!$mydb->query($query)) return 'ESY9002';
			
		return $result;
	}

Android Studio IDE 錯誤

 :app:compile xxxxx JavaWithJavac FAILED An exception has occurred in the compiler (1.8.0_312). Please file a bug against the Java compiler ...