はじめてのAppsFlyer: (2) iOS SDK実装／iOSシミュレーターでの動作確認

AppsFlyerを利用する場合、計測対象とするアプリにSDKをインストールし実装を行います。
[AppsFlyer Developer Hub](https://ja.dev.appsflyer.com/hc/docs/ios-sdk)に詳細な手順があり、iOSエンジニアの方であれば、特に迷うことなく実装できると思います。

この記事では、はじめの一歩として、Apple Developer Programに登録していなくても簡単にできる範囲で、アプリへのAppsFlyer SDKインストール・実装とiOSシミュレーターでの動作確認までを解説します。

iOSエンジニアではないけど、少しSDK実装を体験してみたい方などに参考になればうれしいです。

# 前提・環境
- AppsFlyer管理画面より、アプリIDとDevキーは事前に取得されているものとします。（参考：[前記事「はじめてのAppsFlyer: (1)アプリを管理画面に追加する」](https://qiita.com/maktag/items/5d3399e2137947bef529)）
- Xcode14を利用し、プロジェクトのinterfaceはStoryboardで、言語はSwiftという設定で作られているものとして解説しています。
- iOSシミュレーターでのアプリ実行の場合、端末を識別するためのUserAgentやIDFAの情報が取得できないため、非オーガニックインストール（広告接触に紐づくインストール）の計測はできず、オーガニックインストールの確認までとなります。（非オーガニックインストールを含む計測の動作確認には、実機デバイスでのアプリ実行が必要になります。）

# AppsFlyer SDKのインストール（Swift Package Managerの場合）

まず、AppsFlyer SDKのライブラリをインストールします。インストール方法としては、以下のいずれかで行うこととなります。
- CocoaPodsを利用
- Carthageを利用
- Swift Package Manager (SPM, V6.1.0+)を利用
- 手動で静的フレームワークをインポート

ここでは、一番新しくて簡単な方法である Swift Package Manager でのインストール手順で進めます。

## 1 - Swift Package Managerのパッケージ追加画面を開く
Xcodeのプロジェクトを開き、File > Add Packagesのメニューへ進んでください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73759/3215e1e7-f543-0af8-8db4-0a84926d2fab.png)


## 2 - AppsFlyerFrameworkを選択
iOS SDKのGitHubリポジトリのURL"https://github.com/AppsFlyerSDK/AppsFlyerFramework" を入力し検索。AppsFlyerFrameworkが出てきますので、これを選び、インストールするSDKバージョンを入力します。（最新版を使うのであればデフォルトのままでOKです）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73759/d3e5bd34-bb19-0462-581d-eb6a5b064d95.png)

## 3 - AppsFlyerLibのTargetとしてXcodeプロジェクトを選択

すでにプロジェクト名が入っていればそのまま「Add Package」で完了します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73759/74fd4282-b834-090e-225a-d4ee49b812fd.png)

## 4 - Package DependenciesにAppsFlyerLibの追加を確認

Xcodeプロジェクトの左メニュー内のPackage Dependenciesに「AppsFlyerLib」が追加されていればOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73759/1228517d-4b03-eb5f-149c-1a6623c65d22.png)

ここまででSDKインストールは完了です。良い時代になりました。


# AppsFlyer SDK実装

## 1 - SDKライブラリのインポート

まず、先ほどSwiftPackage Managerに追加したAppsFlyerLibをインポートします。

```swift:AppDelegate.swift
import AppsFlyerLib
```

## 2 - SDKの初期化
`didFinishLaunchingWithOptions`内で`AppsFlyerLib`を呼び出すための初期化処理を記述します。
- appsFlyerDevKeyとappleAppIDに、それぞれ**Devキー**と**アプリID**をセットします。
- 今回は検証目的でデバッグログを確認するため、isDebugを有効化します。
- selfを使用して、AppDelegateをAppsFlyerLib.shared().delegateに割り当てます。この後、AppDelegateを拡張したAppsFlyerLibDelegateで、計測のコールバックメソッド（onConversionDataSuccess等）を利用するためです。


```swift:AppDelegate.swift
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        AppsFlyerLib.shared().appsFlyerDevKey = "kvxxxxxxxxxxxxxxxxxxEC"
        AppsFlyerLib.shared().appleAppID = "id1111xxxxx"
        AppsFlyerLib.shared().isDebug = true /* To see debug log. Remove before the release */
        AppsFlyerLib.shared().delegate = self
        
       // ...
    }
//...
}
```

:::note warn
デバッグログでは、SDKとAppsFlyerサーバー間のRequest/Responseが確認できるため検証時には便利ですが、機密情報の漏えい予防のため、**アプリをリリースする際にはisDebugを必ず無効化**してください。
:::

## 3 - SDKの開始

`SceneDelegate`クラスを利用している場合には: `didFinishLaunchingWithOptions`内で、`UIApplicationDidBecomeActiveNotification`オブザーバーを追加し、`AppsFlyerLib.shared().start()`を実行するようにします。
Xcode11以降では、プロジェクト内に`SceneDelegate`が自動生成されているので、そのまま使う場合はこちらになります。


```swift:AppDelegate.swift
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//...
       // SceneDelegate support
        NotificationCenter.default.addObserver(self, selector: NSSelectorFromString("sendLaunch"), name: UIApplication.didBecomeActiveNotification, object: nil)
        return true
    }
    // SceneDelegate support
    @objc func didBecomeActiveNotification() {
        AppsFlyerLib.shared().start()
    }
//...
}
```

ちなみに、iOS12以前のアプリにも対応が必要などの理由で`SceneDelegate`を利用しない場合には、下記のように`applicationDidBecomeActive`内でstartを実装します。

```swift:AppDelegate.swift
func applicationDidBecomeActive(_ application: UIApplication) {
    AppsFlyerLib.shared().start()
    // ...
}
```

## 4 - AppsFlyerLibDelegateの実装

`AppDelegate`を拡張した`AppsFlyerLibDelegate`を追加し、インストール計測のコールバックに基づく処理を記述します。

- `onConversionDataSuccess`は、インストール計測に成功した場合に呼び出され、取得したコンバージョンデータを利用できます。
- `onConversionDataFailure`は、`onConversionDataSuccess`が失敗した場合に呼び出されます。取得できるエラーを元に、ユーザーに期待される処理を記述します。

```swift:AppDelegate.swift
extension AppDelegate: AppsFlyerLibDelegate {
     
    // Handle Organic/Non-organic installation
    func onConversionDataSuccess(_ data: [AnyHashable: Any]) {
        print("onConversionDataSuccess data:")
        for (key, value) in data {
            print(key, ":", value)
        } 
        if let status = data["af_status"] as? String {
            if (status == "Non-organic") {
                if let sourceID = data["media_source"],
                    let campaign = data["campaign"] {
                    print("This is a Non-Organic install. Media source: \(sourceID)  Campaign: \(campaign)")
                }
            } else {
                print("This is an organic install.")
            }
            if let is_first_launch = data["is_first_launch"] as? Bool,
                is_first_launch {
                print("First Launch")
            } else {
                print("Not First Launch")
            }
        }
    }
    
    func onConversionDataFail(_ error: Error) {
        print("\(error)")
    }
}

```

ここまでのコードが実装できていれば、SDKの実装はとりあえず完了！
インストールの計測ができるはずです。


# iOSシミュレーターでの動作確認

iOS Simulatorsの中から適当な端末を選んで実行してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73759/ac533a8e-5ab1-2a73-e1e9-a80db9a973f0.png)

少し時間がかかるかもしれませんがシミュレーターが起動し、アプリがインストールされて、起動するはずです。（上記以外の実装をしていない場合には、真っ白な画面が開くだけですが）

Xcodeの右下にはログが出力されるはずです。

![Monosnap AdventTest — AppDelegate.swift 2022-12-18 01-12-57(1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73759/c4c167d5-d1d2-49f3-0b96-8a3e1fc3ffac.png)

このログの中に下記のように`statusCode = 200`の記載があれば、AppsFlyer SDKが動作し、サーバーとのデータの授受ができています。

```
2022-12-17 18:23:06.302508+0900 AdventTest[34110:313760] [AppsFlyerSDK] [com.appsflyer.serial] [HTTP] 
Result: {
    data = {length = 2, bytes = 0x6f6b};
    dataStr = ok;
    retries = 2;
    statusCode = 200;
    taskIdentifier = 2;
} 
```

`statusCode = 400`などの場合には、DevキーやアプリIDが間違ったりしていないかを確認してみてください。
また、このようなstatusCode自体が見当たらず、"No network route"などの文字がみられる場合には、シミュレーターが通信できる状態か（シミュレーター内のSafariを開いて、Webサイトが見れるか？）を確認してみてください。

また、下記のようなログから、オーガニックインストールとして正しく計測できており、`onConversionDataSuccess`の処理も問題なく動いていることが確認できます。

```
2022-12-17 18:23:09.129122+0900 AdventTest[34110:313760] [AppsFlyerSDK] [com.appsflyer.serial] [GCD-A02] -[AdventTest.AppDelegate onConversionDataSuccess:]:
{
    "af_message" = "organic install";
    "af_status" = Organic;
    "is_first_launch" = 1;
}
2022-12-17 18:23:09.131263+0900 AdventTest[34110:313759] [AppsFlyerSDK] [com.appsflyer.serial] [GCD-A03] Server retrieving finished
onConversionDataSuccess data:
af_message : organic install
af_status : Organic
is_first_launch : 1
This is an organic install.
First Launch
```


# AppsFlyerオーバービュー上の表示

ここまでログで確認できていれば、AppsFlyer管理画面のオーバービューにもインストール計測結果として、数値が反映されるようになるはずです。
（インストール発生からオーバービュー上での表示までは15–30分程度のタイムラグがあります。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73759/5d662a19-2a9f-5c2b-af4a-a6d508885819.png)

# まとめ

この記事では、アプリへのAppsFlyer SDKインストール・実装とiOSシミュレーターでの動作確認までを解説しました。
あまりSwiftでの開発経験がない方でも、やってみていただければ、SDK実装はそんなに難しくないということがご理解いただけるかと思います。

とはいえ、広告効果を測定するためには、やはり**非オーガニック計測**ができてナンボですし、iOSの場合には**ATTポップアップ**を表示する実装を加えないとIDFAが取得できません。
次回以降の記事では、そのあたりの内容を書いていきます。