Unity Cloud BuildでFirebaseを使ったiOSアプリをビルドする

Unity Cloud BuildではCocoapodが使えません。
なのでCocoapodを使わずにFirebaseの機能をiOSで使う方法を紹介します。
##使えた機能
* Analytics
* Realtime Database
* Authentication
* Cloud Messaging
* Dynamic Links　

##UnityにFirebaseを実装する
###FirebaseのSDKを入れる
まず [ここ](https://firebase.google.com/download/unity?authuser=0 "Unity Firebase SDK") からFirebaseのUnity用のSDKをダウンロードします。
次にダウンロードしたSDKをUnityにインポートします。
[Assets]>[Import Package]>[Custom Package...]
![2019-11-05 (3)_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357553/d2eac027-f995-83ff-5464-ef3fc8f204ce.jpeg)
ダウンロードしたzipファイルから使うものを選びます
Downloads\firebase_unity_sdk_6.6.0\firebase_unity_sdk\dotnet4\
↑このパスの中の Firebase???.unitypackage
###iOSのFrameworkを入れる
次にFirebaseのiOS版のFrameworkを [ここ](https://firebase.google.com/download/ios?authuser=0 "iOS Firebase SDK") からダウンロードします。
ダウンロードしたzipファイルを解凍し、使いたいFirebaseの機能のファイルを開く。
####Analyticsの場合
[Downloads/Firebase-6.11.0/Firebase/Analytics]内のすべての .framework フォルダを
Unityの[Assets/Plugins/iOS]に入れます。
![2019-11-05 (8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357553/ed072ffb-3b72-1882-a86e-b23727a4665e.png)
こんな感じでその他のframeworkも入れていきます。
frameworkが入れ終わったら、[Firebase-6.11.0\Firebase]内にある
[Firebase.h]というファイルも[Assets/Plugins/iOS]に入れます。
##XcodeをC#で設定する
下のファイルを[Assets/Editor]内に置きます。
###BuildProcess.cs

```csharp:BuildProcess.cs
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
public class BuildProcess
{
    [PostProcessBuild]
    public static void OnPostProcessBuild(BuildTarget buildTarget, string path)
    {
        // iOSじゃなければ処理しない
        if (buildTarget != BuildTarget.iOS)
        {
            return;
        }
        var project = new PBXProject();
        project.ReadFromFile(PBXProject.GetPBXProjectPath(path));
        var projectGuid = project.TargetGuidByName(PBXProject.GetUnityTargetName());
        // Enable Modules (C and Objective-C)をYESに設定する
        project.SetBuildProperty(projectGuid, "CLANG_ENABLE_MODULES", "YES");
        project.SetBuildProperty(projectGuid, "ENABLE_BITCODE", "NO");
        project.WriteToFile(PBXProject.GetPBXProjectPath(path));
        string projPath = Path.Combine(path, "Unity-iPhone.xcodeproj/project.pbxproj");
        PBXProject proj = new PBXProject();
        proj.ReadFromString(File.ReadAllText(projPath));
        string target = proj.TargetGuidByName("Unity-iPhone");
        proj.AddBuildProperty(target, "OTHER_LDFLAGS", "-ObjC");//　必須！
        proj.AddBuildProperty(target, "OTHER_LDFLAGS", "-l???");
/*
詳しくは下を参照
*/
        List<string> frameworks = new List<string>() {
            "???.framework"
        };
        foreach (var framework in frameworks)
        {
            proj.AddFrameworkToProject(target, framework, false);
        }
        File.WriteAllText(projPath, proj.WriteToString());
        CreateEntitlements(path, "myapp");
        SetCapabilities(path);// Push通知を使わないなら多分いらない
    }
    private static void CreateEntitlements(string path, string your_appname)
    {
        XmlDocument document = new XmlDocument();
        XmlDocumentType doctype = document.CreateDocumentType("plist", "-//Apple//DTD PLIST 1.0//EN", "http://www.apple.com/DTDs/PropertyList-1.0.dtd", null);
        document.AppendChild(doctype);
        XmlElement plist = document.CreateElement("plist");
        plist.SetAttribute("version", "1.0");
        XmlElement dict = document.CreateElement("dict");
        plist.AppendChild(dict);
        document.AppendChild(plist);
        XmlElement e = (XmlElement)document.SelectSingleNode("/plist/dict");
        XmlElement key = document.CreateElement("key");
        key.InnerText = "aps-environment";
        e.AppendChild(key);
        XmlElement value = document.CreateElement("string");
        value.InnerText = "development";
        e.AppendChild(value);
        string entitlementsPath= Path.Combine(path, "Unity-iPhone/" + your_appname + ".entitlements");
         //= path + "/Unity-iPhone/" + your_appname + ".entitlements";
        document.Save(entitlementsPath);
        string projPath = Path.Combine(path, "Unity-iPhone.xcodeproj/project.pbxproj");
        PBXProject proj = new PBXProject();
        proj.ReadFromString(File.ReadAllText(projPath));
        string target = proj.TargetGuidByName("Unity-iPhone");
        string guid = proj.AddFile(entitlementsPath, entitlementsPath);
        proj.AddBuildProperty(target, "CODE_SIGN_ENTITLEMENTS", Path.Combine(path, "Unity-iPhone/" + your_appname + ".entitlements"));
        proj.AddFileToBuild(target, guid);
        proj.WriteToFile(projPath);
    }
    private static void SetCapabilities(string path)
    {
        string projPath = Path.Combine(path, "Unity-iPhone.xcodeproj/project.pbxproj");
        PBXProject proj = new PBXProject();
        proj.ReadFromString(File.ReadAllText(projPath));
        string target = proj.TargetGuidByName("Unity-iPhone");
        bool s=proj.AddCapability(target, PBXCapabilityType.PushNotifications);
        File.WriteAllText(projPath, proj.WriteToString());
        string[] lines = proj.WriteToString().Split('\n');
        List<string> newLines = new List<string>();
        bool editFinish = false;
        for (int i = 0; i < lines.Length; i++)
        {
            string line = lines[i];
            if (editFinish)
            {
                newLines.Add(line);
            }
            else if (line.IndexOf("isa = PBXProject;") > -1)
            {
                do
                {
                    newLines.Add(line);
                    line = lines[++i];
                } while (line.IndexOf("TargetAttributes = {") == -1);
                // この下のやつは多分無くても大丈夫　まあ、一応・・・
                newLines.Add("TargetAttributes = {");
                newLines.Add("********* = {");
                newLines.Add("DevelopmentTeam = ****;");
                newLines.Add("SystemCapabilities = {");
                newLines.Add("com.apple.BackgroundModes = {");
                newLines.Add("enabled = 1;");
                newLines.Add("};");
                newLines.Add("com.apple.Push = {");
                newLines.Add("enabled = 1;");
                newLines.Add("};");
                newLines.Add("};");
                newLines.Add("};");
                editFinish = true;
            }
            else
            {
                newLines.Add(line);
            }
        }
        File.WriteAllText(projPath, string.Join("\n", newLines.ToArray()));
    }
}
```
###IOSBuildPostProcessor.cs

```csharp:IOSBuildPostProcessor.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;

public static class IOSBuildPostProcessor
{
    [PostProcessBuild]
    public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
    {
        if (target == BuildTarget.iOS)
        {
            OnPostprocessBuildIOS(pathToBuiltProject);//Dynamic Links用
            OnPostprocessBuildPush(pathToBuiltProject);//Cloud Messaging用
            OnPostprocessBuildbg(pathToBuiltProject);//Cloud Messaging用
        }
    }

    private static void OnPostprocessBuildIOS(string pathToBuiltProject)
    {
        //This is the default path to the default pbxproj file. Yours might be different
        string projectPath = "/Unity-iPhone.xcodeproj/project.pbxproj";
        //Default target name. Yours might be different
        string targetName = "Unity-iPhone";
        //Set the entitlements file name to what you want but make sure it has this extension
        string entitlementsFileName = "my_app.entitlements";

        var entitlements = new ProjectCapabilityManager(pathToBuiltProject + projectPath, entitlementsFileName, targetName);
        var domain = "？？？.page.link"; //ここにはDynamic Linksで設定した、？？？.page.linkなどを入れる
        entitlements.AddAssociatedDomains(new string[] { "applinks:" + domain });
        //Apply
        entitlements.WriteToFile();
    }
    private static void OnPostprocessBuildPush(string pathToBuiltProject)
    {
        //This is the default path to the default pbxproj file. Yours might be different
        string projectPath = "/Unity-iPhone.xcodeproj/project.pbxproj";
        //Default target name. Yours might be different
        string targetName = "Unity-iPhone";
        //Set the entitlements file name to what you want but make sure it has this extension
        string entitlementsFileName = "my_app_2.entitlements";

        var entitlements = new ProjectCapabilityManager(pathToBuiltProject + projectPath, entitlementsFileName, targetName);
        entitlements.AddPushNotifications(true);
        //Apply
        entitlements.WriteToFile();
    }
    private static void OnPostprocessBuildbg(string pathToBuiltProject)
    {
        //This is the default path to the default pbxproj file. Yours might be different
        string projectPath = "/Unity-iPhone.xcodeproj/project.pbxproj";
        //Default target name. Yours might be different
        string targetName = "Unity-iPhone";
        //Set the entitlements file name to what you want but make sure it has this extension
        string entitlementsFileName = "my_app_3.entitlements";

        var entitlements = new ProjectCapabilityManager(pathToBuiltProject + projectPath, entitlementsFileName, targetName);
        entitlements.AddBackgroundModes(BackgroundModesOptions.RemoteNotifications);
        //Apply
        entitlements.WriteToFile();
    }
}

```

長いですね・・・
コメントを見て少し書き換えたりしてください。

###BuildProcess.csを書き換える
```csharp:BuildProcess.cs

        proj.AddBuildProperty(target, "OTHER_LDFLAGS", "-ObjC");//　必須！
        proj.AddBuildProperty(target, "OTHER_LDFLAGS", "-l???");
        List<string> frameworks = new List<string>() {
            "???.framework"
        };
     
```
上のBuildProcess.csにこんな行があると思います
ここをframeworkファイル内の**module.modulemap**に沿って書き換えます。
####例 Analyticsの場合
場所 [FirebaseAnalytics.framework/Modules/module.modulemap]

```text:module.modulemap
framework module FirebaseAnalytics {
  umbrella header "FirebaseAnalytics.h"
  export *
  module * { export * }
  link "sqlite3"
  link "z"
  link framework "CoreData"
  link framework "Security"
  link framework "StoreKit"
  link framework "SystemConfiguration"
  link framework "UIKit"
}

```
と書いてある場合は
`proj.AddBuildProperty(target, "OTHER_LDFLAGS", "-ObjC");//　必須！`
の下に
`proj.AddBuildProperty(target, "OTHER_LDFLAGS", "-lz");`
`proj.AddBuildProperty(target, "OTHER_LDFLAGS", "-lsqlite3");`
を追加します。
要するに
 "-l"+"link の後に書いているもの"
を追加します。
`link framework`の部分は、
`List<string> frameworks = new List<string>() {`
の中に上の例では

```csharp
"CoreData.framework",
"Security.framework",
"StoreKit.framework",
"SystemConfiguration.framework",
"UIKit.framework"
```
を追加します。

こんな感じで他のframeworkのmodule.modulemapを見て追加します。

後はビルドしてみましょう！
そうすれば多分できるはずです。

わからないことやエラーが起きたらコメントで知らせてください。