Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Reworked CocoaPod helper class used in Google Play Games Services plugin for Unity, to append Podfiles instead of attempting to copy if they don't exist.
// <copyright file="CocoaPodHelper.cs" company="Google Inc.">
// Copyright (C) 2014 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using System.Text;
#if UNITY_IPHONE && !NO_GPGS
namespace GooglePlayGames.Editor
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using UnityEditor;
using UnityEditor.Callbacks;
public class CocoaPodHelper
{
enum PodFileParseState
{
ReadingPlatform,
ReadingTarget,
ReadingPostInstall
}
static Dictionary<string, string> platforms = new Dictionary<string, string>();
static Dictionary<string, string> dependecies = new Dictionary<string, string>();
static Dictionary<string, string> buildSettings = new Dictionary<string, string>();
//static readonly string endToken = "end";
static readonly string platformToken = "platform";
//static readonly string targetToken = "target";
static readonly string podToken = "pod";
static readonly string postInstallToken = "post_install";
static readonly string configToken = "config.";
// pod can be in 2 places. El Capitain does not allow
// installs into /usr/bin, so pod ends up in /usr/local/bin
private static string[] podPaths = {
"/usr/bin/pod",
"/usr/local/bin/pod"
};
public static void AppendPodfile(string pathToBuiltProject, string pathToAppendingPodfile)
{
UnityEngine.Debug.LogFormat ("Appending {0} to podfile", pathToAppendingPodfile);
UnityEngine.Debug.LogFormat ("Dependency count {0}", dependecies.Count);
string[] lines = File.ReadAllLines (pathToAppendingPodfile);
PodFileParseState state = PodFileParseState.ReadingPlatform;
foreach (string line in lines) {
switch (state) {
case PodFileParseState.ReadingPlatform:
// Check for platform
if (line.StartsWith (platformToken)) {
string[] split = line.Split (':');
string platform = split [1].Trim ();
string version = "";
if (platform.Contains (",")) {
split = platform.Split (',');
platform = split [0].Trim ();
version = split [1].Trim ();
}
UnityEngine.Debug.LogFormat ("platform found {0}", platform);
if (platforms.ContainsKey (platform)) {
// string cleanVersion = version.Replace ("'", "");
// string cleanCurrentVersion = platforms [platform].Replace ("'", "");
//
// UnityEngine.Debug.LogFormat ("clean version = {0}", cleanVersion);
// UnityEngine.Debug.LogFormat ("current version = {0}", cleanCurrentVersion);
//
// Version current = new Version (cleanCurrentVersion);
// Version toCheck = new Version (cleanVersion);
//
// if (toCheck > current) {
// platforms [platform] = version;
// }
} else {
platforms.Add (platform, version);
}
// Can only have one platform for now - KISS
state = PodFileParseState.ReadingTarget;
}
break;
case PodFileParseState.ReadingTarget:
// Check for pods
// We keep it simple where all pods will be used in both 'Unity-iPhone' and 'Unity-iPhone Tests' targets
if (line.StartsWith (postInstallToken)) {
UnityEngine.Debug.Log ("Changing to look for Post Install settings");
state = PodFileParseState.ReadingPostInstall;
} else if (line.StartsWith (podToken)) {
string podData = line.Substring (4).Trim ();
string podName = podData;
string podVersion = "";
if (podData.Contains (",")) {
string[] split = podData.Split (',');
podName = split [0].Trim ();
podVersion = split [1].Trim ();
}
UnityEngine.Debug.LogFormat ("pod found {0} {1}", podName, podVersion);
if (dependecies.ContainsKey (podName)) {
// Need to do something funky here later
// As this can be of different levels (~>, <=, =, >= etc)
} else {
dependecies.Add (podName, podVersion);
}
}
break;
case PodFileParseState.ReadingPostInstall:
// check for build settings
if (line.Trim ().StartsWith (configToken)) {
string[] split = line.Split ('=');
string configSetting = split [0].Trim();
string configSettingValue = split [1].Trim ();
buildSettings [configSetting] = configSettingValue;
}
break;
}
}
}
private static void GeneratePodFile(string pathToBuiltProject) {
string destpodfile = pathToBuiltProject + "/Podfile";
StringBuilder podFileLines = new StringBuilder ();
podFileLines.AppendLine ("source 'https://github.com/CocoaPods/Specs.git'");
podFileLines.AppendLine ();
// Platform
foreach (KeyValuePair<string, string> kvp in platforms) {
podFileLines.AppendFormat ("platform :{0}", kvp.Key);
if (kvp.Value.Length > 0) {
podFileLines.AppendFormat (", {0}", kvp.Value);
}
podFileLines.AppendLine ();
}
podFileLines.AppendLine ();
podFileLines.AppendLine ("target 'Unity-iPhone' do");
// Unity-iPhone target
foreach (KeyValuePair<string, string> kvp in dependecies) {
podFileLines.AppendFormat ("\tpod {0}", kvp.Key);
if (kvp.Value.Length > 0) {
podFileLines.AppendFormat (", {0}", kvp.Value);
}
podFileLines.AppendLine ();
}
podFileLines.AppendLine ("end");
podFileLines.AppendLine ();
podFileLines.AppendLine ("target 'Unity-iPhone Tests' do");
// Unity-iPhone Tests target
foreach (KeyValuePair<string, string> kvp in dependecies) {
podFileLines.AppendFormat ("\tpod {0}", kvp.Key);
if (kvp.Value.Length > 0) {
podFileLines.AppendFormat (", {0}", kvp.Value);
}
podFileLines.AppendLine ();
}
podFileLines.AppendLine ("end");
podFileLines.AppendLine ();
// Post install
podFileLines.AppendLine ("post_install do |installer|");
podFileLines.AppendLine ("\tinstaller.pods_project.targets.each do |target|");
podFileLines.AppendLine ("\t\ttarget.build_configurations.each do |config|");
foreach (KeyValuePair<string, string> kvp in buildSettings) {
podFileLines.AppendFormat ("\t\t\t{0} = {1}", kvp.Key, kvp.Value);
podFileLines.AppendLine ();
}
podFileLines.AppendLine ("\t\tend");
podFileLines.AppendLine ("\tend");
podFileLines.AppendLine ("end");
File.WriteAllText (destpodfile, podFileLines.ToString ());
}
// Set to Max to run at the end
[PostProcessBuild(int.MaxValue)]
public static void OnPostProcess(BuildTarget target, string pathToBuiltProject)
{
// Generate Podfile
if (target == BuildTarget.iOS || target == BuildTarget.tvOS) {
// Generate Podfile
GeneratePodFile (pathToBuiltProject);
// Run pod update
CocoaPodHelper.Update (pathToBuiltProject);
}
}
public static bool Update(string projDir)
{
string podPath = null;
foreach (string p in podPaths)
{
if (File.Exists(p))
{
podPath = p;
}
}
if (podPath == null || !File.Exists(podPath))
{
UnityEngine.Debug.LogError("pod executable not found: " + podPath);
return false;
}
if (!Directory.Exists(projDir))
{
UnityEngine.Debug.LogError("project not found: " + projDir);
return false;
}
return ExecuteCommand("update", projDir);
}
private static bool ExecuteCommand(string command, string projDir)
{
string podPath = null;
foreach (string p in podPaths)
{
if (File.Exists(p))
{
podPath = p;
}
}
if (podPath == null || !File.Exists(podPath))
{
UnityEngine.Debug.LogError("pod executable not found: " + podPath);
return false;
}
using (var process = new Process())
{
if (!process.StartInfo.EnvironmentVariables.ContainsKey("LANG"))
{
process.StartInfo.EnvironmentVariables.Add("LANG", "en_US.UTF-8");
}
process.StartInfo.WorkingDirectory = projDir;
process.StartInfo.FileName = podPath;
process.StartInfo.Arguments = command;
UnityEngine.Debug.Log("Executing " + podPath + " command: " +
process.StartInfo.Arguments);
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
try
{
process.Start();
process.StandardError.ReadToEnd();
var stdOutput = process.StandardOutput.ReadToEnd();
var stdError = process.StandardError.ReadToEnd();
UnityEngine.Debug.Log("pod stdout: " + stdOutput);
if (stdError != null && stdError.Length > 0)
{
UnityEngine.Debug.LogError("pod stderr: " + stdError);
}
if (!process.WaitForExit(10 * 1000))
{
throw new Exception("pod did not exit in a timely fashion");
}
return process.ExitCode == 0;
}
catch (Exception e)
{
throw new Exception(
"Encountered unexpected error while running pod",
e);
}
}
}
}
}
#endif
@SilkyPantsDan

This comment has been minimized.

Copy link
Owner Author

@SilkyPantsDan SilkyPantsDan commented Apr 11, 2016

Then change in GPGSPostBuild.cs where the podfile is copied (Line 115) to:

    string podfile = "Assets/GooglePlayGames/Editor/Podfile.txt";
    CocoaPodHelper.AppendPodfile (pathToBuiltProject, podfile);

    GPGSInstructionWindow w = EditorWindow.GetWindow<GPGSInstructionWindow>(
        true,
        "Building for IOS",
        true);
    w.minSize = new UnityEngine.Vector2(400, 300);
    w.UsingCocoaPod = true;

And if using the AdMob plugin, also change the copy (Line 36) to the following:

string podfile = "Assets/GoogleMobileAds/Editor/Podfile";
CocoaPodHelper.AppendPodfile (path, podfile);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.