Work In Progress

We know everyone wants documentation for all the wonderful components, and it's getting done slowly. We just are including things into the package faster then we can create lovely documentation for it. We'd rather get the tools out there as soon as possible, and then catch up on documentation after. We can only hope you understand our dilemma.

A highly optimized 2D AudioClip pooling system built from the ground up for awesomeness. Utilized by studios across a multitude of platforms, this is battle tested and ready to rock!

Overview

From as simple as handling UI sound effects to the managing of a complex ambient soundscape, the Hydrogen.Core.AudioStack can do it all at the same time! This system allows for anyone to easily play 2D AudioClips on demand or cached in the most optimal way possible. When an Hydrogen.Core.AudioStackItem is told to be played, the system intelligently picks an available AudioSource to play the Hydrogen.Core.AudioStackItem, and when completed returns the AudioSource back to the stack for future use.

The hAudioStack Singleton creates an instance of Hydrogen.Core.AudioStack which can be globally accessed via hAudioStack.Instance.

AudioStackItem

The Hydrogen.Core.AudioStackItem class is a representation of all information related to a particular AudioClip playing, both in and outside of the hAudioStack.

When you use hAudioStack.Instance.Add and pass it an AudioClip, a new instance of a Hydrogen.Core.AudioStackItem will be created on the fly for you related to the information passed through arguments to it and subsequently use it appropriately. The class has numerous fields and methods publicly accessible, however it should not often be managed directly as the hAudioStack handles all of it automatically in most cases.

Usage

There really isn't much to using the hAudioStack, it is one of those solutions that is meant to have a very minimal footprint code wise but can be easily expanded on to accommodate for much larger goals. Typically, you are just going to be using hAudioStack.Instance.Add in a fire-and-forget manner to accomplish what you want.

2D AudioClips Only (Sorta!)

The Hydrogen.Core.AudioStack is built to use any 2D AudioClips, as the location of the AudioSource does not matter while playing. However, nothing is stopping you from using 3D AudioClips if you would like, just be aware that the location of the AudioSource is set to a child GameObject's position.

Public Fields

Type Name Description
int MaximumSources Maximum number of sources to have in total (Stack + Playing).
int MinimumSources Minimum number of sources to have in total (Stack + Playing).
bool Persistent Should the hAudioStack instance (and it's GameObject) survive scene switches by using GameObject.DontDestroyOnLoad. This will preserve all scripts on its GameObject as well, so please be aware of that behaviour.
bool UsePriorities Should the stack look at the priority of the existing AudioStackItems playing, and if the stack is full stop the lowest and use it's newly available source to play the new item. It should be noted that this will ignore any playing sources that are set to loop.

Properties

Type Access Name Description
hAudioStack get Instance Returns the static hAudioStack instance (Thread Safe Singleton).
Dictionary <string, Hydrogen.Core.AudioStackItem> get LoadedItems Gets all currently loaded AudioStackItems.
int get SourcesCount Returns the number of currently being used, based on the number of loaded AudioStackItems.

Public Methods

static bool Exists ()

Does a hAudioStack instance exist?
None
// Let's see if we are using the hAudioStack component.
if (hAudioStack.Exists ()) {
	// Yes - We are that awesome.
	Debug.Log ("A AudioStack Already Exists");
}
Type Value Description
bool true An instance of hAudioStack already exists. This can be handy to simply check from other classes if hAudioStack is being used.
bool false An instance of hAudioStack does not exist, and therefore must be created or instantiated via a prefab.

string Add (AudioClip clip)

Add/Load an Hydrogen.Core.AudioStackItem which is created dynamically from the passed AudioClip.
Type Name Description
AudioClip clip An AudioClip to be used to create a new Hydrogen.Core.AudioStackItem from.
// Example Data
public AudioClip ourClip;
string _ourKey;

// Let's just use Unity's function for fun.
void Awake ()
{
	// Add (and by default AutoPlay) the clip.
	_ourKey = hAudioStack.Instance.Add (ourClip);
	
	// Show some output love!
	Debug.Log ("Our Assigned Key: " + _ourKey);
}
Type Description
string The Dictionary's key for future use and reference of the added Hydrogen.Core.AudioStackItem.

string Add (AudioClip clip, bool createDuplicate)

Add/Load an Hydrogen.Core.AudioStackItem which is created dynamically from the passed AudioClip.
Type Name Description
AudioClip clip An AudioClip to be used to create a new Hydrogen.Core.AudioStackItem from.
bool createDuplicate Should a duplicate entry be made, even if an existing Hydrogen.Core.AudioStackItem is found in the AudioStack? Duplicates will have a custom key generated for them at runtime.
// Example Data
public AudioClip ourClip;
string _ourKey;

// Let's just use Unity's function for fun.
void Awake ()
{
	// Add (and by default AutoPlay) the clip.
	_ourKey = hAudioStack.Instance.Add (ourClip, true);
	
	// Show some output love!
	Debug.Log ("Our Assigned Key: " + _ourKey);
}
Type Description
string The Dictionary's key for future use and reference of the added Hydrogen.Core.AudioStackItem.

string Add (Hydrogen.Core.AudioStackItem item)

Add/Load an Hydrogen.Core.AudioStackItem.
Type Name Description
Hydrogen.Core.AudioStackItem item An Hydrogen.Core.AudioStackItem to be added.
// Example Data
public Hydrogen.Core.AudioStackItem ourItem;
string _ourKey;

// Let's just use Unity's function for fun.
void Awake ()
{
	// Fun Stuff -- Cause We Can
	ourItem.PlayOnLoad = false;
	ourItem.Loop = true;
	
	// Add (and by default AutoPlay) the clip.
	_ourKey = hAudioStack.Instance.Add (ourItem);
	
	// Show some output love!
	Debug.Log ("Our Assigned Key: " + _ourKey);
}
Type Description
string The Dictionary's key for future use and reference of the added Hydrogen.Core.AudioStackItem.

string Add (Hydrogen.Core.AudioStackItem item, bool createDuplicate)

Add/Load an Hydrogen.Core.AudioStackItem.
Type Name Description
Hydrogen.Core.AudioStackItem item An Hydrogen.Core.AudioStackItem to be added.
bool createDuplicate Should a duplicate entry be made, even if an existing Hydrogen.Core.AudioStackItem is found in the AudioStack? Duplicates will have a custom key generated for them at runtime.
// Example Data
public Hydrogen.Core.AudioStackItem ourItem;
string _ourKey;

// Let's just use Unity's function for fun.
void Awake()
{
	// Fun Stuff -- Cause We Can
	ourItem.PlayOnLoad = false;
	ourItem.Loop = true;
	
	// Add (and by default AutoPlay) the clip.
	_ourKey = hAudioStack.Instance.Add (ourItem, true);
	
	// Show some output love!
	Debug.Log ("Our Assigned Key: " + _ourKey);
}
Type Description
string The Dictionary's key for future use and reference of the added Hydrogen.Core.AudioStackItem.

bool IsLoaded (AudioClip clip)

Determines whether the AudioClip is loaded via a Hydrogen.Core.AudioStackItem in the Hydrogen.Core.AudioStack.
Type Name Description
AudioClip clip The target AudioClip to check if found in the Hydrogen.Core.AudioStack.
// Example Data
AudioClip ourTarget;

// Let's check it out!
if (hAudioStack.Instance.IsLoaded (ourTarget))
{
	// Yup we got it!
	Debug.Log ("AudioClip Found");
}
Type Value Description
bool true The AudioClip was found in the Hydrogen.Core.AudioStack.
bool false The AudioClip does not exist in the Hydrogen.Core.AudioStack.

bool IsLoaded (Hydrogen.Core.AudioStackItem item)

Determines whether the Hydrogen.Core.AudioStackItem is in the Hydrogen.Core.AudioStack.
Type Name Description
Hydrogen.Core.AudioStackItem item The target Hydrogen.Core.AudioStackItem to check if found in the Hydrogen.Core.AudioStack.
// Example Data
Hydrogen.Core.AudioStackItem ourTarget;

// Let's check it out!
if (hAudioStack.Instance.IsLoaded (ourTarget))
{
	// Yup we got it!
	Debug.Log ("AudioStackItem Found");
}
Type Value Description
bool true The Hydrogen.Core.AudioStackItem was found in the Hydrogen.Core.AudioStack.
bool false The Hydrogen.Core.AudioStackItem does not exist in the Hydrogen.Core.AudioStack.

bool IsLoaded (string key)

Determines whether something is loaded in the Hydrogen.Core.AudioStack by reference to it's key.
Type Name Description
string key The reference key to check against in the Hydrogen.Core.AudioStack.
// Let's check it out!
if (hAudioStack.Instance.IsLoaded ("myKey"))
{
	// Yup we got it!
	Debug.Log ("Item Found Using Key");
}
Type Value Description
bool true Something was found in the Hydrogen.Core.AudioStack using the specified key.
bool false Nothing was found in the Hydrogen.Core.AudioStack using the specified key.

bool IsPlaying (AudioClip clip)

Determines whether the AudioClip is playing via a Hydrogen.Core.AudioStackItem in the Hydrogen.Core.AudioStack.
Type Name Description
AudioClip clip The target AudioClip to check if playing in the Hydrogen.Core.AudioStack.
// Example Data
AudioClip ourTarget;

// Let's check it out!
if (hAudioStack.Instance.IsPlaying (ourTarget))
{
	// Yup we got it!
	Debug.Log ("AudioClip Playing");
}
Type Value Description
bool true The AudioClip was playing in the Hydrogen.Core.AudioStack.
bool false The AudioClip was not playing in the Hydrogen.Core.AudioStack.

bool IsPlaying (Hydrogen.Core.AudioStackItem item)

Determines whether the Hydrogen.Core.AudioStackItem is playing in the Hydrogen.Core.AudioStack.
Type Name Description
Hydrogen.Core.AudioStackItem item The target Hydrogen.Core.AudioStackItem to check if playing in the Hydrogen.Core.AudioStack.
// Example Data
Hydrogen.Core.AudioStackItem ourTarget;

// Let's check it out!
if (hAudioStack.Instance.IsPlaying (ourTarget))
{
	// Yup we got it!
	Debug.Log ("AudioStackItem Playing");
}
Type Value Description
bool true The Hydrogen.Core.AudioStackItem was playing in the Hydrogen.Core.AudioStack.
bool false The Hydrogen.Core.AudioStackItem was not playing in the Hydrogen.Core.AudioStack.

bool IsPlaying (string key)

Determines whether something is playing in the Hydrogen.Core.AudioStack by reference to it's key.
Type Name Description
string key The reference key to check against in the Hydrogen.Core.AudioStack.
// Let's check it out!
if (hAudioStack.Instance.IsPlaying ("myKey"))
{
	// Yup we got it!
	Debug.Log ("Item Playing Using Key");
}
Type Value Description
bool true Something was playing in the Hydrogen.Core.AudioStack using the specified key.
bool false Nothing was playing in the Hydrogen.Core.AudioStack using the specified key.

void Remove (AudioClip clip)

Removes the specified AudioClip and it's associated Hydrogen.Core.AudioStackItem from the Hydrogen.Core.AudioStack.
Type Name Description
AudioClip clip The target AudioClip to be removed from the Hydrogen.Core.AudioStack.
// Example Data
AudioClip targetClip;

// Free up some resources!
hAudioStack.Instance.Remove (targetClip);
Nothing

void Remove (Hydrogen.Core.AudioStackItem item)

Removes the Hydrogen.Core.AudioStackItem from the Hydrogen.Core.AudioStack.
Type Name Description
Hydrogen.Core.AudioStackItem item The target Hydrogen.Core.AudioStackItem to be removed from the Hydrogen.Core.AudioStack.
// Example Data
Hydrogen.Core.AudioStackitem targetItem;

// Let's Add It For Kicks.
hAudioStack.Instance.Add (targetItem);

// Free up some resources! Bye bye!
hAudioStack.Instance.Remove (targetItem);
Nothing

void Remove (string key)

Remove the Hydrogen.Core.AudioStackItem associated to the specified key in the Hydrogen.Core.AudioStack.
Type Name Description
string key The reference key to check against in the Hydrogen.Core.AudioStack.
// Removing can be this easy - Sometimes.
hAudioStack.Instance.Remove ("someKey");
Nothing
No more building coroutines to handle your web postings, you give it a destination, payload, and a callback; it handles the rest. Now if only making a game could be this easy.

Overview

Why does making a simple REST API (for example) call require more then a single line of code? No more we say! We have created a system that provides a "fire and forget" solution to Unity when it comes to web based interactions via GET, POST, and FORM data.

The hWebPool Singleton creates an instance of Hydrogen.Core.WebPool which can be globally accessed via hWebPool.Instance.

ObjectPool Required

The Hydrogen.Core.WebPool relies on the Hydrogen.Core.ObjectPool to enable the pooling side of things. It will automatically create one in the scene at runtime if there is not one present.

Usage

The guiding principle is that you can fire off as many web calls as you would like (limited by the the pool size), and the Hydrogen.Core.WebPool will manage and handle the rest for you. Eventually we would like to see this being done entirely on a separate thread, however that would require including System.Net, which has a rather hefty distribution size.

Public Fields

Type Name Description
bool Persistent Should the hWebPool instance (and it's GameObject) survive scene switches by using GameObject.DontDestroyOnLoad. This will preserve all scripts on its GameObject as well, so please be aware of that behaviour.

Properties

Type Access Name Description
hWebPool get Instance Returns the static hWebPool instance (Thread Safe Singleton).

Public Methods

static bool Exists ()

Does a hWebPool instance exist?
None
// Let's see if we are using the hWebPool component.
if (hWebPool.Exists ()) {
	// Yes - We are that awesome.
	Debug.Log ("A WebPool Already Exists");
}
Type Value Description
bool true An instance of hWebPool already exists. This can be handy to simply check from other classes if hWebPool is being used.
bool false An instance of hWebPool does not exist, and therefore must be created or instantiated via a prefab.

void Form (string URI, Dictionary<string,string> formStringData)

HTTP POST Form to URI.
Type Name Description
string URI The URI (aka URL) to which the form and it's data should be posted to.
Dictionary<string,string> formStringData The form's data to be sent in the POST.
// Example Data
var formData = new Dictionary<string, string>();
formData.Add ("username", "batman");
formData.Add("password", "robin");

// Send it on it's way!
hWebPool.Instance.Form("http://api.unityforge.net/", formData);
Nothing
HTTP POST Form to URI.
Type Name Description
string URI The URI (aka URL) to which the form and it's data should be posted to.
Dictionary<string,string> formStringData The form's data to be sent in the POST.
Hydrogen.Core.WebPool.FormBinaryData[] formBinaryData A custom struct used to store binary data. Useful for uploading pictures.
string cookie Any previous cookie data to be used for authentication.
Action<int, Hashtable, string> callback A callback function (int hash, Hashtable headers, string payload).
// Example Data
var _response;

// Let's just Unity's own legacy GUI system to display these things quickly.
public void OnGUI()
{
	if ( GUI.Button(new Rect(10,10, 100, 30), "GO!") )
	{
		// Local Example Data
		var formData = new Dictionary<string, string>();
		formData.Add ("username", "batman");
		formData.Add("password", "robin");
		
		// Send it on it's way!
		hWebPool.Instance.Form("http://api.unityforge.net/", formData, null, null, Finished);
	}
	
	// Show the response, always.
	GUI.Label (new Rect (25, 90, 500, 500), _response);
}

// Our fancy Action (delegate) function that is called when the worker is finished.
// It is important that your Action function meet the same arguements as this one.
public void Finished (int hash, Hashtable responseHeaders, string responseText)
{
	// Make sure that our hash is displayed for verification purposes.
	_response = "CALL-HASH: " + hash + "\n\n";

	// Let's also show the headers that came across in the response as they are very handy for 
	// figuring out if something is wrong. Look at the response code; your hoping for a 200 OK.
	var headers = "HEADERS\n========\n\n";
	foreach (var s in responseHeaders.Keys) {
			headers += s + ": " + responseHeaders [s] + "\n\r";
	}

	// Append that header text to our response text
	_response += headers;

	// Add the actual response payload (if there is one)
	_response += "\n\rRESPONSE-TEXT: \n\r==============\n\r" + responseText;
}
Nothing

void GET (string URI)

HTTP GET Request to URI
Type Name Description
string URI The URI (aka URL) which should be accessed.
// Simply access the URI, handy for signalling an event via URL arguements
hWebPool.Instance.Get("http://api.unityforge.net/?honey=imhome", );
Nothing

void GET (string URI, Action<int, Hashtable, string> callback)

HTTP GET Request to URI
Type Name Description
string URI The URI (aka URL) which should be accessed.
Action<int, Hashtable, string> callback A callback function (int hash, Hashtable headers, string payload).
// Example Data
var _response;

// Let's just Unity's own legacy GUI system to display these things quickly.
public void OnGUI()
{
	if ( GUI.Button(new Rect(10,10, 100, 30), "GO!") )
	{
		// Let's access that URI and grab the response!
		hWebPool.Instance.GET("http://api.unityforge.net/?honey=imhome", Finished);
	}
	
	// Show the response, always.
	GUI.Label (new Rect (25, 90, 500, 500), _response);
}

// Our fancy Action (delegate) function that is called when the worker is finished.
// It is important that your Action function meet the same arguements as this one.
public void Finished (int hash, Hashtable responseHeaders, string responseText)
{
	// Make sure that our hash is displayed for verification purposes.
	_response = "CALL-HASH: " + hash + "\n\n";

	// Let's also show the headers that came across in the response as they are very handy for 
	// figuring out if something is wrong. Look at the response code; your hoping for a 200 OK.
	var headers = "HEADERS\n========\n\n";
	foreach (var s in responseHeaders.Keys) {
			headers += s + ": " + responseHeaders [s] + "\n\r";
	}

	// Append that header text to our response text
	_response += headers;

	// Add the actual response payload (if there is one)
	_response += "\n\rRESPONSE-TEXT: \n\r==============\n\r" + responseText;
}
Nothing
HTTP GET Request to URI
Type Name Description
string URI The URI (aka URL) which should be accessed.
string cookie Any previous cookie data to be used for authentication.
Action<int, Hashtable, string> callback A callback function (int hash, Hashtable headers, string payload).
// Example Data
var _response;
var _cookie = "name=value; name2=value2";

// Let's just Unity's own legacy GUI system to display these things quickly.
public void OnGUI ()
{
	if (GUI.Button (new Rect(10,10, 100, 30), "GO!"))
	{
		// Let's access that URI and grab the response!
		hWebPool.Instance.GET("http://api.unityforge.net/?honey=imhome", _cookie, Finished);
	}
	
	// Show the response, always.
	GUI.Label (new Rect (25, 90, 500, 500), _response);
}

// Our fancy Action (delegate) function that is called when the worker is finished.
// It is important that your Action function meet the same arguements as this one.
public void Finished (int hash, Hashtable responseHeaders, string responseText)
{
	// Make sure that our hash is displayed for verification purposes.
	_response = "CALL-HASH: " + hash + "\n\n";

	// Let's also show the headers that came across in the response as they are very handy for 
	// figuring out if something is wrong. Look at the response code; your hoping for a 200 OK.
	var headers = "HEADERS\n========\n\n";
	foreach (var s in responseHeaders.Keys) {
			headers += s + ": " + responseHeaders [s] + "\n\r";
	}

	// Append that header text to our response text
	_response += headers;

	// Add the actual response payload (if there is one)
	_response += "\n\rRESPONSE-TEXT: \n\r==============\n\r" + responseText;
}
Nothing

void POST (string URI, string contentType, string payload)

HTTP POST Request to URI.
Type Name Description
string URI The URI (aka URL) which data should be posted too.
string contentType The classification of the content (Example: "application/json").
string payload The data to be posted to the target URI.
// Create new JSONObject for our payload
var jsonPayload = new Hydrogen.Serialization.JSONObject ();

// Initial setup of payload
jsonPayload.Fields.Add ("apikey", "398c1161326cef46dad0e0a340a38e6b-us7");
jsonPayload.Fields.Add ("id", "c0eaf9ec60");

// Lazy example for a sub JSONObject; you can create JSON objects from JSON.
jsonPayload.Fields.Add ("email", new Hydrogen.Serialization.JSONObject (
		"{\"email\":\"" + "test@test.com" + "\"}"));

// Send POST to the WebPool
hWebPool.Instance.POST (
	"https://us7.api.mailchimp.com/2.0/lists/subscribe.json",
	"application/json",
	jsonPayload.Serialized);
Nothing

void POST (string URI, string contentType, string payload, string cookie, Action<int, Hashtable, string> callback)

HTTP POST Request to URI.
Type Name Description
string URI The URI (aka URL) which data should be posted too.
string contentType The classification of the content (Example: "application/json").
string payload The data to be posted to the target URI.
string cookie Any previous cookie data to be used for authentication.
Action<int, Hashtable, string> callback A callback function (int hash, Hashtable headers, string payload).
// Example Data
var _response;
var _cookie = "name=value; name2=value2";

// Let's just Unity's own legacy GUI system to display these things quickly.
void OnGUI ()
{
	if (GUI.Button (new Rect (25, 60, 90, 20), "Subscribe")) {

		// Create new JSONObject
		var jsonPayload = new Hydrogen.Serialization.JSONObject ();

		// Initial setup of payload
		jsonPayload.Fields.Add ("apikey", "398c1161326cef46dad0e0a340a38e6b-us7");
		jsonPayload.Fields.Add ("id", "c0eaf9ec60");

		// Lazy example for a sub JSONObject; you can create JSON objects from JSON.
		jsonPayload.Fields.Add ("email", new Hydrogen.Serialization.JSONObject (
			"{\"email\":\"" + "test@test.com" + "\"}"));

		// Send POST to the WebPool
		hWebPool.Instance.POST (
			"https://us7.api.mailchimp.com/2.0/lists/subscribe.json",
			"application/json",
			jsonPayload.Serialized,
			_cookie,
			MailChimpCallback);
	}

	// Show Response
	GUI.Label (new Rect (25, 90, 500, 500), _response);
}

// Our fancy Action (delegate) function that is called when the worker is finished.
// It is important that your Action function meet the same arguements as this one.
public void MailChimpCallback (int hash, Hashtable responseHeaders, string responseText)
{
	// Make sure that our hash is displayed for verification purposes.
	_response = "CALL-HASH: " + hash + "\n\n";
	
	// Let's also show the headers that came across in the response as they are very handy for 
	// figuring out if something is wrong. Look at the response code; your hoping for a 200 OK.
	var headers = "HEADERS\n========\n\n";
	foreach (var s in responseHeaders.Keys) {
		headers += s + ": " + responseHeaders [s] + "\n\r";
	}
	
	// Append that header text to our response text
	_response += headers;
	
	// Add the actual response payload (if there is one)
	_response += "\n\rRESPONSE-TEXT: \n\r==============\n\r" + responseText;
}
Nothing

Public Structs

FormBinaryData

When dealing with binary data on a FORM submission, Hydrogen.Core.WebPool utilizes a handy struct to facilitate packaging of the corresponding data.

Type Name Description
string FieldName The name of the form field.
byte[] Data The byte data to populate that field with.
string FileName The file name of the data that has been populated.
string MimeType The internet media type of the data.
An automatic installation paired with a robust implementation. What could be more awesome? OK fine, we will start to think about including a "Make Game" button.

Overview

TestFlight is a free platform used to distribute beta and internal iOS/Android applications to team members over-the-air. Developers can manage beta testing campaigns and receive feedback from their team with TestFlight's dashboard. With the TestFlight SDK implemented in an application, users can acquire more metrics on how and what testers are doing when testing an application on their device.

TestFlight Documentation

With that much awesomeness bundled into one package we felt the need to make sure that every Unity developer was able to easily integrate and deploy with TestFlight. Hydrogen's TestFlight component (and supporting scripts) work on the principle of handling as much of the grunt work as possible, allowing you to focus on more important tasks; like making an awesome game.

The hTestFlight Singleton creates an instance of Hydrogen.Plugins.TestFlight which can be globally accessed via hTestFlight.Instance. As always, this is merely one way of extending on the Hydrogen.Plugins.TestFlight class, as it is designed to be decoupled from everything, you can create your own implementation if you would like (and have the time!).

Installation

TestFlight - iOS Install

Inside of the Assets menu (on Unity's menu bar!), we have added a TestFlight sub-menu; under that we have placed two magical items to automatically complete the install process for both iOS and Android. By selecting either of these options a nice automated installer will popup (with a fancy progress bar) and handle the below processes for you.

These automated processes rely on the folder structure of Hydrogen not being altered in any way; while you can move the Hydrogen folder wherever you like, its contents need to stay as they are, if you would like the automated installation script to function correctly. If you are eager to install and use a newer version of TestFlight (it takes a little while for the Asset Store to approve a package), you most certainly can replace the library files (iOS v2.2.1 / Android v1.4) found in Vendors/TestFlight folder under the packages root. You can however replace the TestFlight library files found in the Vendors/TestFlight folder with newer versions of the library if you do not wish to use the provided versions.

We have done our best to try and accommodate for all sorts of scenarios; however we are only human and sometimes things come up that could potentially break the install script. Therefore, we have included the following as a checklist to make sure that the installation has been completed properly.

Preprocessor Directive

One of the great features about the implementation of TestFlight in Hydrogen is that even with platforms that TestFlight does not support, your code will still work unchanged and it won't include or reference anything that isn't going to be used. This nice treat requires that a preprocessor directive (HYDROGEN_TESTFLIGHT) is used. The installation script automatically adds the directive to the Scripting Define Symbols found in Unity's Player Settings corresponding platform. If you are having problems with getting TestFlight to work, please make sure to double check that your desired platform has the directive added to it's Scripting Define Symbols.

iOS Checklist

TestFlight - iOS Plugins Folder
The following files should be copied into the Plugins/iOS folder, preferably at the root of your projects Assets folder. These files are specific to TestFlights iOS implementation, including our additional set of helper functions that help our Unity implementation.
  • HydrogenTestFlight.mm
  • libTestFlight.a
  • TestFlight.h
  • TestFlight+AsyncLogging.h
  • TestFlight+ManualSessions.h
If any of these files are missing from the Plugins/iOS folder after you have used the install menu item, you will more then likely need to copy them there yourself manually. They are available in the Vendors/TestFlight/iOS and Extras/TestFlight/Android folders in the Hydrogen Framework root.
TestFlight - Scripting Define Symbols
This is an important part of the verification process, as it seems to be the highest point of issue. When the installer runs for a specific platform, it adds the HYDROGEN_TESTFLIGHT symbol to the Scripting Define Symbols found in the Unity's Player Settings. This tells our scripts to include the necessary portions of code for that platform and makes everything work nicely (Vague Statements FTW). However, there are times where the Player Settings might get overwritten by another user's commit to a project which accidentally removes this symbol. It is always a good idea to verify the symbol is present for your desired platform if things are not working for you.
TestFlight - iOS AppToken

The next thing you need to do is make sure that TestFlight is ready to receive data from your application. This entails making sure you've created an App on their end and have put in the correct Bundle Identifier (found in the Unity's Player Settings).

Once you have the App created with TestFlight you will be able to get access to the generated App Token. This is going to be used in the next step, so keep the window open and handy.

TestFlight - Component

Last but not least, you need to add either the lovely drop in Component (MonoBehaviour) for TestFlight (hTestFlight) to a GameObject or you can implement your own based on Hydrogen.Plugins.TestFlight.

No matter what, your going to need that App Token from TestFlight, and will either put it in the Token iOS field of the hTestFlight component or however your implementation takes it.

Android Checklist

TestFlight - Android Plugins Folder
The following files should be copied into the Plugins/Android folder, preferably at the root of your projects Assets folder. Something to make a note of is that the AndroidManifest.xml is created for you automatically if you do not already have one present in the folder. If one exists, the install script will add the necessary permissions to it for you.
  • AndroidManifest.xml
  • res/raw/tf.properties
  • TestFlightLib.jar
If any of these files are missing from the Plugins/Android folder after you have used the install menu item, you will more then likely need to copy them there yourself manually. They are available in the Vendors/TestFlight/Android and Extras/TestFlight/Android folders in the Hydrogen Framework root.
TestFlight - Scripting Define Symbols
This is an important part of the verification process, as it seems to be the highest point of issue. When the installer runs for a specific platform, it adds the HYDROGEN_TESTFLIGHT symbol to the Scripting Define Symbols found in the Unity's Player Settings. This tells our scripts to include the necessary portions of code for that platform and makes everything work nicely (Vague Statements FTW). However, there are times where the Player Settings might get overwritten by another user's commit to a project which accidentally removes this symbol. It is always a good idea to verify the symbol is present for your desired platform if things are not working for you.
TestFlight - Android AppToken

The next thing you need to do is make sure that TestFlight is ready to receive data from your application. This entails making sure you've created an App on their end and have put in the correct Bundle Identifier (found in the Unity's Player Settings).

Once you have the App created with TestFlight you will be able to get access to the generated App Token. This is going to be used in the next step, so keep the window open and handy.

TestFlight - Component

Last but not least, you need to add either the lovely drop in Component (MonoBehaviour) for TestFlight (hTestFlight) to a GameObject or you can implement your own based on Hydrogen.Plugins.TestFlight.

No matter what, your going to need that App Token from TestFlight, and will either put it in the Token Android field of the hTestFlight component or however your implementation takes it.

Usage

Now that you have gotten all the installation done, it's time to start rocking away with the actual component! For the sake of documentation it is assumed that you are using the provided hTestFlight component. If you have implemented your own version of the Hydrogen.Plugins.TestFlight class its safe to say that you may not really need to look over these next few sections.

Public Fields

Type Name Description
bool Persistent Should the hTestFlight instance (and it's GameObject) survive scene switches by using GameObject.DontDestroyOnLoad. This will preserve all scripts on its GameObject as well, so please be aware of that behaviour.
string TokenIOS The generated App Token for the iOS App registered with TestFlight. You can find this token mentioned in the above iOS Checklist Step 3.
string TokenAndroid The generated App Token for the Android App registered with TestFlight. You can find this token mentioned in the above Android Checklist Step 3.

Properties

Type Access Name Description
hTestFlight get Instance Returns the static hTestFlight instance (Thread Safe Singleton).

Public Methods

static bool Exists ()

Does a hTestFlight instance exist?
None
// Let's see if we are using the hTestFlight component.
if (hTestFlight.Exists ()) {
	// Yes - We are that awesome.
	Debug.Log ("hTestFlight Already Exists");
}
Type Value Description
bool true An instance of hTestFlight already exists. This can be handy to simply check from other classes if hTestFlight is being used, for piping debug output to TestFlight for example.
bool false An instance of hTestFlight does not exist, and therefore must be created or instantiated via a prefab.

void AddCustomEnvironmentInformation (string key, string data) iOS ONLY

Adds an entry into the Key-Value store for this TestFlight session.
Type Name Description
string key The Key
string data The Data
// Example Data
string userName = "Batman";

// Somehow we've managed to detected that Batman is our user.
if (userName == "Batman") {
	// We need to report this ... RIGHT NOW!
	hTestFlight.Instance.AddCustomEnvironmentInformation ("User", userName);
}
Nothing

void Log (string message)

Send a message to TestFlight to appear in it's console.
Type Name Description
string message The message to be sent to and logged by TestFlight.
// Example Data
int batRepellent;

// Does Batman have repellent?
if (batRepellent <= 0) {
	hTestFlight.Instance.Log ("Error! Batman Doesn't Have A Repellent For This!");
}
Nothing

void LogAsync (string message) iOS ONLY

Send a message to TestFlight asynchronously to appear in it's console.
Type Name Description
string message The message to be sent to and logged by TestFlight.
// Example Data
bool moreBatRepellent;

// Does Batman have more repellent?
if (!moreBatRepellent) {
	hTestFlight.Instance.LogAsync ("Error! Batman Doesn't Have More Repellent!");
}
Nothing

void PassCheckpoint (string checkpoint)

Report to TestFlight that the session has passed a Checkpoint.
Type Name Description
string checkpoint This is the checkpoint that should be reported to TestFlight. This can be any string that you want, but it is recommended that you stick to meaningful descriptive entries.
// Example Data
int buttonCount;
bool buttonPressed;

// Loop for no reason whatsoever
while (buttonCount < 100) {
	// Magic!
	buttonPressed = true;
	
	// Did Batman press the button?
	if (buttonPressed) {
		buttonCount++;
		buttonPressed = false;
	}
}

// Report that Batman has wasted time! and lots of it.
hTestFlight.Instance.PassChcckpoint ("Batman Pressed The Button 100 Times");
Nothing

void SubmitFeedback (string message) iOS ONLY

Submits a feedback message for the App to TestFlight.
Type Name Description
string message User provided feedback on the current App, or your own if you want to have some fun.
// Example Data
string userFeedback = "I loved your app! It's AWESOME! SHUT UP AND TAKE MY MONEY!";

// Do we have any feedback?
if (!string.IsNullOrEmpty (userFeedback)) {
	hTestFlight.Instance.SubmitFeedback (userFeedback);
}
Nothing