首次提交
This commit is contained in:
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
artifacts/**
|
||||
build/**
|
||||
.build_script/**
|
||||
node_modules/**
|
||||
.DS_Store
|
||||
.npmrc
|
||||
!Documentation~
|
||||
!.Documentation
|
||||
npm-debug.log
|
||||
build.sh.meta
|
||||
build.bat.meta
|
||||
.idea/
|
||||
@@ -0,0 +1,19 @@
|
||||
artifacts/**
|
||||
build/**
|
||||
.build_script/**
|
||||
node_modules/**
|
||||
Documentation/ApiDocs/**
|
||||
Documentation~/ApiDocs/**
|
||||
.DS_Store
|
||||
.npmrc
|
||||
.npmignore
|
||||
.gitignore
|
||||
CONTRIBUTING.md
|
||||
CONTRIBUTING.md.meta
|
||||
QAReport.md
|
||||
QAReport.md.meta
|
||||
.gitlab-ci.yml
|
||||
build.sh
|
||||
build.sh.meta
|
||||
build.bat
|
||||
build.bat.meta
|
||||
@@ -0,0 +1,31 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this package will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.2.0] - 2021-09-21
|
||||
Do not show Context Screen for iOS versions below 14.5
|
||||
Use NSInvocation instead of performSelector for SkAdNetwork methods
|
||||
Expose RequestTrackingAuthorization callback
|
||||
|
||||
## [1.0.0] - 2021-04-22
|
||||
First Stable Release
|
||||
Updates to the Context Screen sample and the README
|
||||
|
||||
## [0.2.0-preview.3] - 2021-04-19
|
||||
Added Context Screen Sample
|
||||
|
||||
## [0.1.0-preview.3] - 2021-04-12
|
||||
Fixed a typo in updateConversionValue
|
||||
|
||||
## [0.1.0-preview.2] - 2020-12-04
|
||||
Fix an issue that caused a warning on some metafiles in Unity 2018.4
|
||||
|
||||
## [0.1.0-preview.1] - 2020-12-04
|
||||
|
||||
### This is the first release of com.unity.ads.ios-support package
|
||||
Add Support for SKADID Spec (Postbuild process automatically adding SKAdNetwork Ids to Info.plsit)
|
||||
Add Support for App Tracking Transparency API's (introduced in ios14)
|
||||
Add Support for SKAdNetwork API's (introduced in ios14)
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2dc7a87feb07749a9855db38a51426d3
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,53 @@
|
||||
# Using this package
|
||||
|
||||
This package supports Apple's SKAdNetwork and AppTrackingTransparency frameworks for your made-with-Unity iOS application, by aggregating proper ad network IDs and providing access to relevant Apple developer APIs.
|
||||
|
||||
For more information about iOS 14 technical integration, including this package's support functionality, please see the full [iOS 14 technical documentation](https://unityads.unity3d.com/help/monetization/ios14).
|
||||
|
||||
## Installing the package
|
||||
|
||||
### From the public Github repository
|
||||
|
||||
1. Go to the [public repo page on Github](https://github.com/Unity-Technologies/com.unity.ads.ios-support).
|
||||
1. Download that repo to your hard drive.
|
||||
2. In the Unity Editor, open the [Unity Package Manager](https://docs.unity3d.com/Manual/Packages.html) window.
|
||||
3. Click the **+** button and select **Add package from disk...**.
|
||||
4. Navigate to the location where you downloaded the repo and select the iOS14 Support package (_..\com.unity.ads.ios-support-master\com.unity.ads.ios-support\package.json_) to install the package. If successful, the iOS14 Support package will appear in the package manager list (note that you must have **All packages** selected to view it).
|
||||
|
||||
### From Unity Package Manager
|
||||
|
||||
1. In the Unity Editor, select **Window** > **Package** Manager to open the Package Manager.
|
||||
2. Select the **Advertisement** package from the list, then select the most recent verified version.
|
||||
3. Click the **Install** or **Update** button.
|
||||
|
||||
## Apple developer API extensions
|
||||
|
||||
This package provides access to the following Apple developer APIs:
|
||||
|
||||
```
|
||||
public static void SkAdNetworkUpdateConversionValue(int conversionValue)
|
||||
```
|
||||
This method allows you to [update the attribution conversion value](https://developer.apple.com/documentation/storekit/skadnetwork/3566697-updateconversionvalue?language=objc).
|
||||
|
||||
```
|
||||
SkAdNetworkRegisterAppForNetworkAttribution()
|
||||
```
|
||||
This method allows you to [register for attribution](https://developer.apple.com/documentation/storekit/skadnetwork/2943654-registerappforadnetworkattributi?language=objc).
|
||||
|
||||
```
|
||||
public static void RequestAuthorizationTracking()
|
||||
```
|
||||
This method allows you to [request the user permission dialogue](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/3547037-requesttrackingauthorization).
|
||||
|
||||
```
|
||||
public static AuthorizationTrackingStatus GetAuthorizationTrackingStatus()
|
||||
```
|
||||
This method allows you to check the app tracking transparency (ATT) [authorization status](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/3547038-trackingauthorizationstatus).
|
||||
|
||||
## Sample Project
|
||||
|
||||
You can import a Context Screen sample scene and assets from the Package Manager screen for this package (Unity 2019.1 and newer).
|
||||
|
||||
The SampleProject~ folder included in the Github public repo is a complete Unity project, compatible with Unity 2018.4.33f1 and up.
|
||||
|
||||
This sample provides a fully customizable example of a context screen you could use to give context to users before showing the native App Tracking Transparency dialog.
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8fbdef3bbd2c4402f9fb8749b4be0cbc
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Copyright 2020
|
||||
//
|
||||
// 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.
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Information about this assembly is defined by the following attributes.
|
||||
// Change them to the values specific to your project.
|
||||
|
||||
[assembly: AssemblyTitle("Unity.Advertisement.IosSupport.Editor")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Unity Technologies")]
|
||||
[assembly: AssemblyProduct("Monetization")]
|
||||
[assembly: AssemblyCopyright("Copyright © Unity Technologies 2020")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
|
||||
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
|
||||
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
|
||||
|
||||
[assembly: AssemblyVersion("0.1.0")]
|
||||
|
||||
[assembly: InternalsVisibleTo("Unity.Advertisement.IosSupport.Editor.Tests")]
|
||||
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe609725aa1304d10bd0232f8a727830
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c12ab5a1ea52495bbfe2f28879f608e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Advertisement.IosSupport.Editor
|
||||
{
|
||||
internal interface ISkAdNetworkParser
|
||||
{
|
||||
string GetExtension();
|
||||
HashSet<string> ParseSource(ISkAdNetworkSource source);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 97e0c61e3aa704af086868b25f08f85a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Unity.Advertisement.IosSupport.Editor
|
||||
{
|
||||
public static class SkAdNetworkFileExtension
|
||||
{
|
||||
public const string XML = "xml";
|
||||
public const string JSON = "json";
|
||||
public const string NONE = "";
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e496c38bf001040ecbe70e444a0542fb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Advertisement.IosSupport.Editor
|
||||
{
|
||||
internal class SkAdNetworkJsonParser : ISkAdNetworkParser
|
||||
{
|
||||
[Serializable]
|
||||
public class SkAdNetworkIdArray
|
||||
{
|
||||
public List<SkAdNetworkInfo> skadnetwork_ids;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class SkAdNetworkInfo
|
||||
{
|
||||
public string skadnetwork_id;
|
||||
}
|
||||
|
||||
public string GetExtension()
|
||||
{
|
||||
return SkAdNetworkFileExtension.JSON;
|
||||
}
|
||||
|
||||
public HashSet<string> ParseSource(ISkAdNetworkSource source)
|
||||
{
|
||||
var foundIds = new HashSet<string>();
|
||||
try
|
||||
{
|
||||
string jsonData;
|
||||
using (var stream = source.Open())
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
Debug.LogWarning($"[Unity SKAdNetwork Parser] Unable to parse SKAdNetwork file: {source.Path}");
|
||||
return foundIds;
|
||||
}
|
||||
|
||||
jsonData = new StreamReader(stream).ReadToEnd();
|
||||
}
|
||||
|
||||
SkAdNetworkIdArray skAdNetworkCompanyInfo = null;
|
||||
try
|
||||
{
|
||||
skAdNetworkCompanyInfo = JsonUtility.FromJson<SkAdNetworkIdArray>(jsonData);
|
||||
}
|
||||
catch (Exception) {}
|
||||
|
||||
//Fallback to try and see if this is a JSONObject which contains an array element called skadnetwork_ids instead of the expected JSONArray
|
||||
if (skAdNetworkCompanyInfo?.skadnetwork_ids == null || skAdNetworkCompanyInfo.skadnetwork_ids.Count == 0)
|
||||
{
|
||||
var updatedJson = "{\"skadnetwork_ids\":" + jsonData + "}";
|
||||
skAdNetworkCompanyInfo = JsonUtility.FromJson<SkAdNetworkIdArray>(updatedJson);
|
||||
}
|
||||
|
||||
if (skAdNetworkCompanyInfo?.skadnetwork_ids == null)
|
||||
{
|
||||
Debug.LogWarning($"[Unity SKAdNetwork Parser] Unable to parse SKAdNetwork file: {source.Path}");
|
||||
return foundIds;
|
||||
}
|
||||
|
||||
foundIds.UnionWith(skAdNetworkCompanyInfo.skadnetwork_ids.Select(t => t.skadnetwork_id).Where(t => t != null));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Debug.LogWarning($"[Unity SKAdNetwork Parser] Unable to parse SKAdNetwork file: {source.Path}");
|
||||
}
|
||||
|
||||
return foundIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9840479aaa6504c9ea96572abd23249c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.Advertisement.IosSupport.Editor
|
||||
{
|
||||
internal static class SkAdNetworkParser
|
||||
{
|
||||
private static Dictionary<string, ISkAdNetworkParser> s_Parsers;
|
||||
|
||||
static SkAdNetworkParser()
|
||||
{
|
||||
s_Parsers = new Dictionary<string, ISkAdNetworkParser>
|
||||
{
|
||||
{ SkAdNetworkFileExtension.XML, new SkAdNetworkXmlParser() },
|
||||
{ SkAdNetworkFileExtension.JSON, new SkAdNetworkJsonParser() },
|
||||
{ SkAdNetworkFileExtension.NONE, new SkAdNetworkUrlParser() }
|
||||
};
|
||||
}
|
||||
|
||||
public static ISkAdNetworkParser GetParser(string parserType)
|
||||
{
|
||||
try
|
||||
{
|
||||
s_Parsers.TryGetValue(parserType, out var parser);
|
||||
return parser;
|
||||
}
|
||||
catch (Exception) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static IEnumerable<ISkAdNetworkParser> GetAllParsers()
|
||||
{
|
||||
return s_Parsers.Values;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f70ff3726241b4d2b8d0ea012c80e706
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Advertisement.IosSupport.Editor
|
||||
{
|
||||
internal class SkAdNetworkUrlParser : ISkAdNetworkParser
|
||||
{
|
||||
public string GetExtension()
|
||||
{
|
||||
return SkAdNetworkFileExtension.NONE;
|
||||
}
|
||||
|
||||
public HashSet<string> ParseSource(ISkAdNetworkSource source)
|
||||
{
|
||||
var foundIds = new HashSet<string>();
|
||||
|
||||
try
|
||||
{
|
||||
string[] lines;
|
||||
using (var reader = new StreamReader(source.Open()))
|
||||
{
|
||||
lines = reader.ReadToEnd().Split(Environment.NewLine.ToCharArray());
|
||||
}
|
||||
|
||||
lines.Where(url => !string.IsNullOrEmpty(url))
|
||||
.Where(url => Uri.IsWellFormedUriString(url, UriKind.Absolute))
|
||||
.ToList().ForEach(url => {
|
||||
ISkAdNetworkParser parser = null;
|
||||
switch (GetExtensionFromPath(url))
|
||||
{
|
||||
case SkAdNetworkFileExtension.XML:
|
||||
parser = SkAdNetworkParser.GetParser(SkAdNetworkFileExtension.XML);
|
||||
break;
|
||||
case SkAdNetworkFileExtension.JSON:
|
||||
parser = SkAdNetworkParser.GetParser(SkAdNetworkFileExtension.JSON);
|
||||
break;
|
||||
}
|
||||
|
||||
if (parser == null)
|
||||
{
|
||||
Debug.LogWarning($"[Unity SKAdNetwork Parser] Unsupported file extension, No parser available to parse SKAdNetwork file: {source.Path} ");
|
||||
return;
|
||||
}
|
||||
|
||||
foundIds.UnionWith(parser.ParseSource(new SkAdNetworkRemoteSource(url)));
|
||||
});
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Debug.LogWarning($"[Unity SKAdNetwork Parser] Unable to parse SKAdNetwork file: {source.Path}");
|
||||
}
|
||||
|
||||
return foundIds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the extension for a filepath string
|
||||
/// </summary>
|
||||
private static string GetExtensionFromPath(string filepath)
|
||||
{
|
||||
var extension = Path.GetExtension(filepath);
|
||||
return string.IsNullOrEmpty(extension) ? "" : extension.Substring(1).ToLower();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 95e1f9f2b229246a08a2354f8c702ae9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Advertisement.IosSupport.Editor
|
||||
{
|
||||
internal class SkAdNetworkXmlParser : ISkAdNetworkParser
|
||||
{
|
||||
private const string k_SkAdNetworkIdentifier = "SKAdNetworkIdentifier";
|
||||
|
||||
public string GetExtension()
|
||||
{
|
||||
return SkAdNetworkFileExtension.XML;
|
||||
}
|
||||
|
||||
public HashSet<string> ParseSource(ISkAdNetworkSource source)
|
||||
{
|
||||
var foundIds = new HashSet<string>();
|
||||
try
|
||||
{
|
||||
var xmlDocument = new XmlDocument();
|
||||
|
||||
using (var stream = source.Open())
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
Debug.LogWarning("[Unity SKAdNetwork Parser] Unable to parse SKAdNetwork file: {source.Path}");
|
||||
return foundIds;
|
||||
}
|
||||
|
||||
xmlDocument.Load(stream);
|
||||
}
|
||||
|
||||
var items = xmlDocument.GetElementsByTagName("key");
|
||||
for (var x = 0; x < items.Count; x++)
|
||||
{
|
||||
if (items[x].InnerText == k_SkAdNetworkIdentifier)
|
||||
{
|
||||
var nextSibling = items[x]?.NextSibling;
|
||||
if (nextSibling != null)
|
||||
{
|
||||
foundIds.Add(nextSibling.InnerText);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Debug.LogWarning($"[Unity SKAdNetwork Parser] Unable to parse SKAdNetwork file: {source.Path}");
|
||||
}
|
||||
|
||||
return foundIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b62c9c75b6cf84b3db11f5bb9f036169
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,118 @@
|
||||
#if UNITY_2018_1_OR_NEWER && UNITY_IOS
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.iOS.Xcode;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.Build.Reporting;
|
||||
|
||||
namespace Unity.Advertisement.IosSupport.Editor
|
||||
{
|
||||
internal class PostProcessBuildPlist : IPostprocessBuildWithReport
|
||||
{
|
||||
public int callbackOrder => 0;
|
||||
private const string k_SkAdNetworkIdentifier = "SKAdNetworkIdentifier";
|
||||
private const string k_SkAdNetworkItems = "SKAdNetworkItems";
|
||||
private const string k_SkAdNetworksFileName = "SKAdNetworks";
|
||||
|
||||
public void OnPostprocessBuild(BuildReport report)
|
||||
{
|
||||
if (report.summary.platform != BuildTarget.iOS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateInfoPlistWithSkAdNetworkIds(report.summary.outputPath);
|
||||
}
|
||||
|
||||
internal static void UpdateInfoPlistWithSkAdNetworkIds(string pathToPlistFile)
|
||||
{
|
||||
var provider = new SkAdNetworkLocalSourceProvider();
|
||||
var ids = new HashSet<string>();
|
||||
try
|
||||
{
|
||||
SkAdNetworkParser.GetAllParsers().ToList().ForEach(parser => {
|
||||
provider.GetSources(k_SkAdNetworksFileName, parser.GetExtension()).ToList().ForEach(source => {
|
||||
ids.UnionWith(parser.ParseSource(source));
|
||||
});
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"Failed to parse SKAdNetwork files due to following reason: {e.Message}");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
WriteSkAdNetworkIdsToInfoPlist(ids, pathToPlistFile);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"Failed to update info.plist file due to following reason: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write all plistValues to an existing Info.plist file
|
||||
/// </summary>
|
||||
internal static void WriteSkAdNetworkIdsToInfoPlist(HashSet<string> skAdNetworkIds, string outputPath)
|
||||
{
|
||||
var infoPlistPath = outputPath + "/Info.plist";
|
||||
var plist = new PlistDocument();
|
||||
plist.ReadFromString(File.ReadAllText(infoPlistPath));
|
||||
var root = plist.root;
|
||||
|
||||
if (root == null)
|
||||
{
|
||||
Debug.LogWarning("[Unity SKAdNetwork Parser] Unable to parse info.plist. Unable to add SkAdNetwork Identifiers.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!root.values?.ContainsKey(k_SkAdNetworkItems) ?? false)
|
||||
{
|
||||
root.CreateArray(k_SkAdNetworkItems);
|
||||
}
|
||||
|
||||
var adNetworkItems = root[k_SkAdNetworkItems].AsArray();
|
||||
|
||||
if (adNetworkItems == null)
|
||||
{
|
||||
Debug.LogWarning("[Unity SKAdNetwork Parser] Unable to modify existing info.plist. Unable to add SkAdNetwork Identifiers.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var adNetworkId in skAdNetworkIds)
|
||||
{
|
||||
if (!PlistContainsAdNetworkId(adNetworkItems, adNetworkId))
|
||||
{
|
||||
adNetworkItems.AddDict().SetString(k_SkAdNetworkIdentifier, adNetworkId);
|
||||
}
|
||||
}
|
||||
|
||||
File.WriteAllText(infoPlistPath, plist.WriteToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the value is already contained in the plist
|
||||
/// </summary>
|
||||
internal static bool PlistContainsAdNetworkId(PlistElementArray adNetworkItems, string adNetworkId)
|
||||
{
|
||||
foreach (var adNetworkItem in adNetworkItems.values)
|
||||
{
|
||||
var item = adNetworkItem.AsDict();
|
||||
if (item.values.TryGetValue(k_SkAdNetworkIdentifier, out var value))
|
||||
{
|
||||
if (value.AsString() == adNetworkId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //UNITY_2018_1_OR_NEWER
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e7bc5a6e424ec49089ca10bdb43d4c42
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2b15b7af045b42dabe70a3914e67cba
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Advertisement.IosSupport.Editor
|
||||
{
|
||||
internal interface ISkAdNetworkSource
|
||||
{
|
||||
string Path { get; }
|
||||
Stream Open();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3b688cb4385c4ed287404f01d47d2cf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Advertisement.IosSupport.Editor
|
||||
{
|
||||
internal class SkAdNetworkLocalSource : ISkAdNetworkSource
|
||||
{
|
||||
public string Path { get; }
|
||||
|
||||
public SkAdNetworkLocalSource(string path)
|
||||
{
|
||||
Path = path;
|
||||
}
|
||||
|
||||
public Stream Open()
|
||||
{
|
||||
return new FileStream(Path, FileMode.Open);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc26fb3115fcd455f8d1d7b9739bc0f5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Unity.Advertisement.IosSupport.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Responsible for finding all SkAdNetwork files on the local filesystem by searching through the users project directory and all includes packages.
|
||||
/// </summary>
|
||||
internal class SkAdNetworkLocalSourceProvider
|
||||
{
|
||||
private const int k_MaxPackageLookupTimeoutInSeconds = 30;
|
||||
private string[] m_PackagePaths;
|
||||
|
||||
public SkAdNetworkLocalSourceProvider()
|
||||
{
|
||||
m_PackagePaths = GetAllPackagePaths();
|
||||
}
|
||||
|
||||
public IEnumerable<SkAdNetworkLocalSource> GetSources(string filename, string extension)
|
||||
{
|
||||
return GetLocalFilePaths(filename, extension).Select(x => new SkAdNetworkLocalSource(x)).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds a file on the local filesystem by looking the project directory, and all package directories
|
||||
/// </summary>
|
||||
/// <param name="filename">the filename to look for</param>
|
||||
/// <param name="fileExtension">the filename extension to look for</param>
|
||||
/// <returns>a full path to the file</returns>
|
||||
private IEnumerable<string> GetLocalFilePaths(string filename, string fileExtension)
|
||||
{
|
||||
return m_PackagePaths
|
||||
.Prepend(Directory.GetCurrentDirectory())
|
||||
.SelectMany(path => Directory.GetFiles(path, string.IsNullOrEmpty(fileExtension) ? filename : $"{filename}.{fileExtension}" , SearchOption.AllDirectories))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of paths to the root folder of each package included in the users project.
|
||||
/// These may be in different locations on disk depending on where the package is being stored/cached.
|
||||
/// </summary>
|
||||
private static string[] GetAllPackagePaths(bool offlineMode = true)
|
||||
{
|
||||
var list = UnityEditor.PackageManager.Client.List(offlineMode);
|
||||
if (list == null)
|
||||
{
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
|
||||
var timeSpan = TimeSpan.FromSeconds(k_MaxPackageLookupTimeoutInSeconds);
|
||||
var startTime = DateTime.Now;
|
||||
while (!list.IsCompleted && (DateTime.Now - startTime) < timeSpan)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
|
||||
if (list.Error != null)
|
||||
{
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
|
||||
return list.Result.Select(packageInfo => packageInfo.assetPath).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5d925f4b6523544bbbfa58d11df1ac49
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Advertisement.IosSupport.Editor
|
||||
{
|
||||
internal class SkAdNetworkRemoteSource : ISkAdNetworkSource
|
||||
{
|
||||
public string Path { get; }
|
||||
|
||||
public SkAdNetworkRemoteSource(string path)
|
||||
{
|
||||
Path = path;
|
||||
}
|
||||
|
||||
public Stream Open()
|
||||
{
|
||||
return new WebClient().OpenRead(Path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fc886aae4a1fc42b48e8b6deccb67ab5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "Unity.Advertisement.IosSupport.Editor",
|
||||
"references": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 782c39a29bdf44a569029c0fc1c6d458
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2020 Unity Technologies
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c8d877d50d36b4851b91aeeafcaa4643
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe90753440b674f63858ab0d9c216a81
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Copyright 2020
|
||||
//
|
||||
// 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.
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Information about this assembly is defined by the following attributes.
|
||||
// Change them to the values specific to your project.
|
||||
|
||||
[assembly: AssemblyTitle("Unity.Advertisement.IosSupport")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Unity Technologies")]
|
||||
[assembly: AssemblyProduct("Monetization")]
|
||||
[assembly: AssemblyCopyright("Copyright © Unity Technologies 2020")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
|
||||
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
|
||||
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
|
||||
|
||||
[assembly: AssemblyVersion("0.1.0")]
|
||||
|
||||
[assembly: InternalsVisibleTo("Unity.Advertisement.IosSupport.Tests")]
|
||||
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7e2daa7c495684110b5f6f4c7b1f0205
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f0517fab4d14c483eb293ee9a3ed62fe
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f8e38b03e8a02476990867b3533da7be
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44d3d607da645444caf451c0ef1b7027
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5666dcb6f872a48299f472e42ea2e4d9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 409380c074b194f2fb87ff280bc34046
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* The class is used in invocation when we want to pass any primitive values to a function with NSInvocation
|
||||
*
|
||||
* @discussion
|
||||
* The problem: NSInvocation category accepts arguments as NSArray that operates with id. We could have used NSValue for those purposes but
|
||||
* in this case we would loose the ability to operate with NSNumbers. NSNumber is subclass of NSValue and since NSInvocation uses typecast to a box
|
||||
* this creates the problem. For that reason NSPrimitivesBox provides the solution by expecting any primitives for a function been wrapped into it
|
||||
*
|
||||
*/
|
||||
@interface UASupportPrimitivesBox : NSValue
|
||||
+ (instancetype)newWithBytes: (nonnull const void *)bytes objCType: (nonnull const char *)type;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09a260cc498cc4d0f833b74d4ed69328
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
#import "UASupportPrimitivesBox.h"
|
||||
#import "UASupportTools.h"
|
||||
|
||||
@interface UASupportPrimitivesBox ()
|
||||
@property (nonatomic, strong) NSValue *box;
|
||||
@end
|
||||
|
||||
@implementation UASupportPrimitivesBox
|
||||
+ (instancetype)newWithBytes: (nonnull const void *)bytes objCType: (nonnull const char *)type {
|
||||
return [[self alloc] initWithBytes: bytes
|
||||
objCType: type];
|
||||
}
|
||||
|
||||
// Suppressing unnecessary warnings. Its expected behaviour when subclassing NSValue, according to the notes from apple docs
|
||||
// https://developer.apple.com/documentation/foundation/nsvalue?language=objc
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wobjc-designated-initializers"
|
||||
- (instancetype)initWithBytes: (const void *)value objCType: (const char *)type {
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wobjc-designated-initializers"
|
||||
SUPER_INIT
|
||||
#pragma GCC diagnostic push
|
||||
self.box = [NSValue valueWithBytes: value
|
||||
objCType: type];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)getValue: (void *)value {
|
||||
return [_box getValue: value];
|
||||
}
|
||||
|
||||
- (const char *)objCType {
|
||||
return [_box objCType];
|
||||
}
|
||||
|
||||
@end
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 61b23861e38444442a4fbeb2ea469fe7
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
tvOS: tvOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*
|
||||
* Category that provides convenience static methods to create and perform invocations.
|
||||
*
|
||||
*/
|
||||
@interface NSInvocation (Category)
|
||||
|
||||
|
||||
/// Invokes a method on a Class or on an instance with a set of arguments
|
||||
/// @note If a target is nil, will try to perform static method on a class.
|
||||
/// @param methodName Full name of a selector
|
||||
/// @param classType Class
|
||||
/// @param target target of type Class
|
||||
/// @param arguments arguments required by the a function
|
||||
///
|
||||
/// @note When we need to pass an enum as an argument, use NSEnumWrapper
|
||||
/// @code NSEnumWrapper *typeWrapped = [NSEnumWrapper newWithBytes:&`EnumValue` objCType: @encode(EnumType)];
|
||||
+ (void)uads_invokeUsingMethod: (NSString *)methodName
|
||||
classType: (Class)classType
|
||||
target: (_Nullable id)target
|
||||
args: (NSArray *)arguments;
|
||||
|
||||
|
||||
/// Creates a prepared NSInvocation to perform a method of a Class or on an instance with a set of arguments
|
||||
/// @note If a target is nil, will try to perform static method on a class.
|
||||
/// @param methodName Full name of a selector
|
||||
/// @param classType Class
|
||||
/// @param target target of type Class
|
||||
/// @param arguments arguments required by the a function
|
||||
///
|
||||
/// @note When we need to pass an enum as an argument, use NSEnumWrapper
|
||||
/// @code NSEnumWrapper *typeWrapped = [NSEnumWrapper newWithBytes:&`EnumValue` objCType: @encode(EnumType)];
|
||||
+ (nullable instancetype)uads_newUsingMethod: (NSString *)methodName
|
||||
classType: (Class)classType
|
||||
target: (_Nullable id)target
|
||||
args: (NSArray *)arguments;
|
||||
|
||||
|
||||
/// Invokes a method on a Class or on an instance with a set of arguments. Returns a result of invoked function
|
||||
/// @note If a target is nil, will try to perform static method on a class.
|
||||
///
|
||||
/// @param methodName Full name of a selector
|
||||
/// @param classType Class
|
||||
/// @param target target of type Class
|
||||
/// @param arguments arguments required by the a function
|
||||
///
|
||||
/// @note When we need to pass an enum as an argument, use NSEnumWrapper
|
||||
/// @code NSEnumWrapper *typeWrapped = [NSEnumWrapper newWithBytes:&`EnumValue` objCType: @encode(EnumType)];
|
||||
+ (nullable id)uads_invokeWithReturnedUsingMethod: (NSString *)methodName
|
||||
classType: (Class)classType
|
||||
target: (_Nullable id)target
|
||||
args: (NSArray *)arguments;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee3d752a5dcf64f46a2c110958ba2126
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
#import "NSInvocation+Convenience.h"
|
||||
#import "UASupportPrimitivesBox.h"
|
||||
#import "UASupportTools.h"
|
||||
|
||||
@implementation NSInvocation (Category)
|
||||
|
||||
+ (void)uads_invokeUsingMethod: (NSString *)methodName
|
||||
classType: (Class)classType
|
||||
target: (_Nullable id)target
|
||||
args: (NSArray *)arguments {
|
||||
NSInvocation *invocation = [self uads_newUsingMethod: methodName
|
||||
classType: classType
|
||||
target: target
|
||||
args: arguments];
|
||||
|
||||
[invocation invoke];
|
||||
}
|
||||
|
||||
+ (nullable id)uads_invokeWithReturnedUsingMethod: (NSString *)methodName
|
||||
classType: (Class)classType
|
||||
target: (_Nullable id)target
|
||||
args: (NSArray *)arguments {
|
||||
__autoreleasing id returnedValue;
|
||||
NSInvocation *invocation = [self uads_newUsingMethod: methodName
|
||||
classType: classType
|
||||
target: target
|
||||
args: arguments];
|
||||
|
||||
[invocation invoke];
|
||||
[invocation getReturnValue: &returnedValue];
|
||||
return returnedValue;
|
||||
}
|
||||
|
||||
+ (nullable instancetype)uads_newUsingMethod: (NSString *)methodName
|
||||
classType: (Class)classType
|
||||
target: (_Nullable id)target
|
||||
args: (NSArray *)arguments {
|
||||
SEL selector = NSSelectorFromString(methodName);
|
||||
|
||||
GUARD_OR_NIL(selector)
|
||||
|
||||
__autoreleasing id targetArg;
|
||||
NSMethodSignature *signature;
|
||||
|
||||
if (!target) {
|
||||
targetArg = classType;
|
||||
signature = [classType methodSignatureForSelector: selector];
|
||||
} else {
|
||||
targetArg = target;
|
||||
signature = [classType instanceMethodSignatureForSelector: selector];
|
||||
}
|
||||
|
||||
GUARD_OR_NIL(signature)
|
||||
|
||||
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: signature];
|
||||
[invocation setSelector: selector];
|
||||
[invocation setTarget: targetArg];
|
||||
|
||||
for (int i = 0; i < [arguments count]; i++) {
|
||||
__autoreleasing id argument = arguments[i];
|
||||
|
||||
UASupportPrimitivesBox *value = uasupport_typecast(argument, [UASupportPrimitivesBox class]);
|
||||
|
||||
if (value) {
|
||||
void *pointerToPrimitives;
|
||||
[value getValue: &pointerToPrimitives];
|
||||
|
||||
/** from https://developer.apple.com/documentation/foundation/nsinvocation/1437834-setargument
|
||||
* An integer specifying the index of the argument.
|
||||
* Indices 0 and 1 indicate the hidden arguments self and _cmd, respectively; you should set these values directly with the target and selector properties. Use indices 2 and greater for the arguments normally passed in a message.
|
||||
*/
|
||||
|
||||
[invocation setArgument: &pointerToPrimitives
|
||||
atIndex: 2 + i];
|
||||
} else {
|
||||
[invocation setArgument: &argument
|
||||
atIndex: 2 + i];
|
||||
}
|
||||
}
|
||||
|
||||
if (!invocation.argumentsRetained) {
|
||||
[invocation retainArguments];
|
||||
}
|
||||
|
||||
return invocation;
|
||||
} /* uads_newUsingMethod */
|
||||
|
||||
@end
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f62205c65beab4f23ae7993dfc41d6f4
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
tvOS: tvOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Macro that replaces boilerplate code like:
|
||||
@code
|
||||
|
||||
if ([obj isKindOfClass: class]) {
|
||||
return obj;
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
*/
|
||||
#define TYPECAST(obj, class) typecast(obj, class)
|
||||
|
||||
/**
|
||||
Macro that replaces boilerplate code when calling super init
|
||||
*/
|
||||
#define SUPER_INIT self = [super init]; if (!self) { return nil; }
|
||||
|
||||
|
||||
/**
|
||||
Convenience macro to check for condition and return nil if false
|
||||
*/
|
||||
#define GUARD_OR_NIL(condition) if (!condition) { return nil; }
|
||||
|
||||
|
||||
_Nullable id uasupport_typecast(id obj, Class class);
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5deb7e6ab2bc42ea9a88ef5e90d83d4
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
#import "UASupportTools.h"
|
||||
|
||||
|
||||
_Nullable id uasupport_typecast(id obj, Class class) {
|
||||
if ([obj isKindOfClass: class]) {
|
||||
return obj;
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a87088279aff24786b336034505be994
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
tvOS: tvOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SkAdNetworkManager.h"
|
||||
|
||||
extern void InterfaceSkAdNetworkUpdateConversionValue(NSInteger conversionValue) {
|
||||
[[SkAdNetworkManager sharedInstance] updateConversionValue:(NSInteger)conversionValue];
|
||||
}
|
||||
|
||||
extern void InterfaceSkAdNetworkRegisterAppForNetworkAttribution() {
|
||||
[[SkAdNetworkManager sharedInstance] registerAppForAdNetworkAttribution];
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 42e354c20cf98414e8592511aefeb841
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
tvOS: tvOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface SkAdNetworkManager : NSObject
|
||||
|
||||
+ (SkAdNetworkManager *)sharedInstance;
|
||||
|
||||
- (BOOL)isAvailable;
|
||||
- (void)updateConversionValue:(NSInteger)conversionValue;
|
||||
- (void)registerAppForAdNetworkAttribution;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,27 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46c89ccf14bf540fbbfe2b3fc0adbc8e
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,105 @@
|
||||
#import "SkAdNetworkManager.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <dlfcn.h>
|
||||
#import <objc/runtime.h>
|
||||
#import <sys/utsname.h>
|
||||
#import "NSInvocation+Convenience.h"
|
||||
#import "UASupportPrimitivesBox.h"
|
||||
|
||||
@interface SkAdNetworkManager ()
|
||||
@property (strong, nonatomic) Class SkAdNetworkClass;
|
||||
@end
|
||||
|
||||
@implementation SkAdNetworkManager
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
if (![SkAdNetworkManager loadFramework]) {
|
||||
NSLog(@"Can't load StoreKit DLL");
|
||||
}
|
||||
self.SkAdNetworkClass = NSClassFromString(@"SKAdNetwork");
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (SkAdNetworkManager *)sharedInstance {
|
||||
static SkAdNetworkManager *instance = nil;
|
||||
static dispatch_once_t token;
|
||||
|
||||
dispatch_once(&token, ^{
|
||||
instance = [[SkAdNetworkManager alloc] init];
|
||||
});
|
||||
return instance;
|
||||
}
|
||||
|
||||
- (void)updateConversionValue:(NSInteger)conversionValue {
|
||||
if (!self.isAvailable) {
|
||||
NSLog(@"SkAdNetwork not available");
|
||||
return;
|
||||
}
|
||||
UASupportPrimitivesBox *index = [UASupportPrimitivesBox newWithBytes: &conversionValue objCType: @encode(NSInteger)];
|
||||
[NSInvocation uads_invokeUsingMethod: @"updateConversionValue:" classType: self.SkAdNetworkClass target: nil args: @[index] ];
|
||||
}
|
||||
|
||||
- (void)registerAppForAdNetworkAttribution {
|
||||
if (!self.isAvailable) {
|
||||
NSLog(@"SkAdNetwork not available");
|
||||
return;
|
||||
}
|
||||
|
||||
[NSInvocation uads_invokeUsingMethod: @"registerAppForAdNetworkAttribution" classType: self.SkAdNetworkClass target: nil args: @[] ];
|
||||
}
|
||||
|
||||
- (BOOL)isAvailable {
|
||||
return self.SkAdNetworkClass != nil;
|
||||
}
|
||||
|
||||
+ (BOOL)isFrameworkPresent {
|
||||
id attClass = objc_getClass("SKAdNetwork");
|
||||
|
||||
if (attClass)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
+ (BOOL)isDeviceSimulator {
|
||||
struct utsname systemInfo;
|
||||
uname(&systemInfo);
|
||||
|
||||
NSString *model = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
|
||||
if ([model isEqualToString:@"x86_64"] || [model isEqualToString:@"i386"])
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
+ (BOOL)loadFramework {
|
||||
NSString *frameworkLocation;
|
||||
|
||||
if (![SkAdNetworkManager isFrameworkPresent]) {
|
||||
NSLog(@"StoreKit.framework is not present, trying to load it.");
|
||||
if ([SkAdNetworkManager isDeviceSimulator]) {
|
||||
NSString *frameworkPath = [[NSProcessInfo processInfo] environment][@"DYLD_FALLBACK_FRAMEWORK_PATH"];
|
||||
if (frameworkPath) {
|
||||
frameworkLocation = [NSString pathWithComponents:@[ frameworkPath, @"StoreKit.framework", @"StoreKit" ]];
|
||||
}
|
||||
} else {
|
||||
frameworkLocation = [NSString stringWithFormat:@"/System/Library/Frameworks/StoreKit.framework/StoreKit"];
|
||||
}
|
||||
dlopen([frameworkLocation cStringUsingEncoding:NSUTF8StringEncoding], RTLD_LAZY);
|
||||
|
||||
if (![SkAdNetworkManager isFrameworkPresent]) {
|
||||
NSLog(@"StoreKit.framework still no present!");
|
||||
return FALSE;
|
||||
} else {
|
||||
NSLog(@"Successfully loaded StoreKit.framework");
|
||||
return TRUE;
|
||||
}
|
||||
} else {
|
||||
NSLog(@"StoreKit.framework already present");
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,37 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f3b9ec31803d4f0aa7c3b0a90910a42
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
tvOS: tvOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "TrackingAuthorizationManager.h"
|
||||
|
||||
|
||||
extern void InterfaceTrackingAuthorizationRequest(TrackingAuthorizationCompletion completion) {
|
||||
[[TrackingAuthorizationManager sharedInstance] trackingAuthorizationRequest:completion];
|
||||
}
|
||||
|
||||
extern NSUInteger InterfaceGetTrackingAuthorizationStatus() {
|
||||
return [[TrackingAuthorizationManager sharedInstance] getTrackingAuthorizationStatus];
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7fd241e3b5fcd40709c2dc9f615a5eff
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
tvOS: tvOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef void (*TrackingAuthorizationCompletion)(NSUInteger status);
|
||||
|
||||
@interface TrackingAuthorizationManager : NSObject
|
||||
|
||||
+ (TrackingAuthorizationManager *)sharedInstance;
|
||||
|
||||
- (BOOL)isAvailable;
|
||||
- (void)trackingAuthorizationRequest:(TrackingAuthorizationCompletion)completion;
|
||||
- (NSUInteger)getTrackingAuthorizationStatus;
|
||||
|
||||
@end
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 25d2f3238e3504e7f90b802740ce28b4
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
#import <AdSupport/AdSupport.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <dlfcn.h>
|
||||
#import <objc/runtime.h>
|
||||
#import <sys/utsname.h>
|
||||
|
||||
#import "TrackingAuthorizationManager.h"
|
||||
|
||||
@interface TrackingAuthorizationManager ()
|
||||
@property (strong, nonatomic) Class trackingManagerAuthorizationClass;
|
||||
@end
|
||||
|
||||
@implementation TrackingAuthorizationManager
|
||||
|
||||
+ (TrackingAuthorizationManager *)sharedInstance {
|
||||
static TrackingAuthorizationManager *instance = nil;
|
||||
static dispatch_once_t token;
|
||||
|
||||
dispatch_once(&token, ^{
|
||||
instance = [[TrackingAuthorizationManager alloc] init];
|
||||
});
|
||||
return instance;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
if (![TrackingAuthorizationManager loadFramework]) {
|
||||
NSLog(@"Can't load ATTrackingManager");
|
||||
}
|
||||
self.trackingManagerAuthorizationClass = NSClassFromString(@"ATTrackingManager");
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isAvailable {
|
||||
return self.trackingManagerAuthorizationClass != nil && [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSUserTrackingUsageDescription"] != nil;
|
||||
}
|
||||
|
||||
- (void)trackingAuthorizationRequest:(TrackingAuthorizationCompletion)completion {
|
||||
if (!self.isAvailable) {
|
||||
if (completion != nil) {
|
||||
completion(0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
id handler = ^(NSUInteger result) {
|
||||
NSLog(@"Result request tracking authorization : %lu", (unsigned long)result);
|
||||
if (completion != nil) {
|
||||
completion(result);
|
||||
}
|
||||
};
|
||||
|
||||
SEL requestSelector = NSSelectorFromString(@"requestTrackingAuthorizationWithCompletionHandler:");
|
||||
if ([self.trackingManagerAuthorizationClass respondsToSelector:requestSelector]) {
|
||||
[self.trackingManagerAuthorizationClass performSelector:requestSelector withObject:handler];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSUInteger)getTrackingAuthorizationStatus {
|
||||
if (!self.isAvailable)
|
||||
return 0;
|
||||
|
||||
NSUInteger value = [[self.trackingManagerAuthorizationClass valueForKey:@"trackingAuthorizationStatus"] unsignedIntegerValue];
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
+ (BOOL)isFrameworkPresent {
|
||||
id attClass = objc_getClass("ATTrackingManager");
|
||||
|
||||
if (attClass)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
+ (BOOL)isDeviceSimulator {
|
||||
struct utsname systemInfo;
|
||||
uname(&systemInfo);
|
||||
|
||||
NSString *model = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
|
||||
if ([model isEqualToString:@"x86_64"] || [model isEqualToString:@"i386"])
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
+ (BOOL)loadFramework {
|
||||
NSString *frameworkLocation;
|
||||
if (![TrackingAuthorizationManager isFrameworkPresent]) {
|
||||
NSLog(@"AppTrackingTransparency Framework is not present, trying to load it.");
|
||||
if ([TrackingAuthorizationManager isDeviceSimulator]) {
|
||||
NSString *frameworkPath = [[NSProcessInfo processInfo] environment]
|
||||
[@"DYLD_FALLBACK_FRAMEWORK_PATH"];
|
||||
if (frameworkPath) {
|
||||
frameworkLocation = [NSString pathWithComponents:@[ frameworkPath, @"AppTrackingTransparency.framework", @"AppTrackingTransparency" ]];
|
||||
}
|
||||
} else {
|
||||
frameworkLocation = [NSString stringWithFormat:@"/System/Library/Frameworks/AppTrackingTransparency.framework/AppTrackingTransparency"];
|
||||
}
|
||||
dlopen([frameworkLocation cStringUsingEncoding:NSUTF8StringEncoding], RTLD_LAZY);
|
||||
|
||||
if (![TrackingAuthorizationManager isFrameworkPresent]) {
|
||||
NSLog(@"AppTrackingTransparency still not present!");
|
||||
return FALSE;
|
||||
} else {
|
||||
NSLog(@"Successfully loaded AppTrackingTransparency framework");
|
||||
return TRUE;
|
||||
}
|
||||
} else {
|
||||
NSLog(@"AppTrackingTransparency framework already present");
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81160d7556a4c4e6bb1b9b8b9e08307f
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 1
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
- first:
|
||||
tvOS: tvOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 43333e0ba2c464cc68cb76c9ee8ec856
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Unity.Advertisement.IosSupport
|
||||
{
|
||||
public class SkAdNetworkBinding
|
||||
{
|
||||
#if UNITY_IOS
|
||||
[DllImport("__Internal")] private static extern void InterfaceSkAdNetworkUpdateConversionValue(int conversionValue);
|
||||
[DllImport("__Internal")] private static extern void InterfaceSkAdNetworkRegisterAppForNetworkAttribution();
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// This method allows you to <a href="https://developer.apple.com/documentation/storekit/skadnetwork/3566697-updateconversionvalue?language=objc">update the attribution conversion value</a>.
|
||||
/// </summary>
|
||||
public static void SkAdNetworkUpdateConversionValue(int conversionValue)
|
||||
{
|
||||
#if UNITY_IOS
|
||||
if (Application.platform == RuntimePlatform.IPhonePlayer)
|
||||
{
|
||||
InterfaceSkAdNetworkUpdateConversionValue(conversionValue);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method allows you to <a href="https://developer.apple.com/documentation/storekit/skadnetwork/2943654-registerappforadnetworkattributi?language=objc">register for attribution</a>.
|
||||
/// </summary>
|
||||
public static void SkAdNetworkRegisterAppForNetworkAttribution()
|
||||
{
|
||||
#if UNITY_IOS
|
||||
if (Application.platform == RuntimePlatform.IPhonePlayer)
|
||||
{
|
||||
InterfaceSkAdNetworkRegisterAppForNetworkAttribution();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7c6e286ebfae4e9cb2c9a51bf24f03e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "Unity.Advertisement.IosSupport",
|
||||
"references": [],
|
||||
"includePlatforms": [
|
||||
"Editor",
|
||||
"iOS"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00c479e63b1c74419820a39073267645
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3dbf8d4cb0fa3468891a620bbe08baad
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Unity.Advertisement.IosSupport
|
||||
{
|
||||
using AOT;
|
||||
public class ATTrackingStatusBinding
|
||||
{
|
||||
#if UNITY_IOS
|
||||
[DllImport("__Internal")] private static extern void InterfaceTrackingAuthorizationRequest(RequestAuthorizationTrackingCompleteHandler callback);
|
||||
[DllImport("__Internal")] private static extern int InterfaceGetTrackingAuthorizationStatus();
|
||||
#endif
|
||||
public delegate void RequestAuthorizationTrackingCompleteHandler(int status);
|
||||
private static RequestAuthorizationTrackingCompleteHandler _requestAuthorizationTrackingCompleteCallback = null;
|
||||
|
||||
/// <summary>
|
||||
/// The enumerated states of an authorization tracking request.
|
||||
/// </summary>
|
||||
public enum AuthorizationTrackingStatus
|
||||
{
|
||||
NOT_DETERMINED = 0,
|
||||
RESTRICTED,
|
||||
DENIED,
|
||||
AUTHORIZED
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method allows you to <a href="https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/3547037-requesttrackingauthorization">request the user permission dialogue</a>.
|
||||
/// </summary>
|
||||
public static void RequestAuthorizationTracking()
|
||||
{
|
||||
RequestAuthorizationTracking(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method allows you to <a href="https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/3547037-requesttrackingauthorization">request the user permission dialogue</a>.
|
||||
/// </summary>
|
||||
public static void RequestAuthorizationTracking(RequestAuthorizationTrackingCompleteHandler callback)
|
||||
{
|
||||
#if UNITY_IOS
|
||||
if (Application.platform != RuntimePlatform.IPhonePlayer) return;
|
||||
if (_requestAuthorizationTrackingCompleteCallback != null)
|
||||
{
|
||||
throw new InvalidOperationException("App tracking transparency request is already triggered and awaiting completion");
|
||||
}
|
||||
_requestAuthorizationTrackingCompleteCallback = callback;
|
||||
InterfaceTrackingAuthorizationRequest(AppTransparencyTrackingRequestCompleted);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method allows you to check the app tracking transparency (ATT) <a href="https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/3547038-trackingauthorizationstatus">authorization status</a>.
|
||||
/// </summary>
|
||||
/// <returns>An <c>AuthorizationTrackingStatus</c> enum value.</returns>
|
||||
public static AuthorizationTrackingStatus GetAuthorizationTrackingStatus()
|
||||
{
|
||||
#if UNITY_IOS
|
||||
if (Application.platform == RuntimePlatform.IPhonePlayer)
|
||||
{
|
||||
return (AuthorizationTrackingStatus)InterfaceGetTrackingAuthorizationStatus();
|
||||
}
|
||||
#endif
|
||||
return AuthorizationTrackingStatus.NOT_DETERMINED;
|
||||
}
|
||||
|
||||
[MonoPInvokeCallback(typeof(RequestAuthorizationTrackingCompleteHandler))]
|
||||
public static void AppTransparencyTrackingRequestCompleted(int status)
|
||||
{
|
||||
_requestAuthorizationTrackingCompleteCallback?.Invoke(status);
|
||||
_requestAuthorizationTrackingCompleteCallback = null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f87f1fe3d04ad4478bf494ee92eabf88
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 32e9af52c87d948b5a76cf37628e731e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"createSeparatePackage": false
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe0974df023424b71866ee559c26bb61
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,45 @@
|
||||
#if UNITY_2018_1_OR_NEWER && UNITY_IOS
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor.iOS.Xcode;
|
||||
|
||||
namespace Unity.Advertisement.IosSupport.Editor.Tests
|
||||
{
|
||||
public class PListTests
|
||||
{
|
||||
[SetUp]
|
||||
public void BeforeEach()
|
||||
{
|
||||
File.Copy("Assets/Info_Test.plist", "Assets/Info.plist");
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void AfterEach()
|
||||
{
|
||||
File.Delete("Assets/Info.plist");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("Assets/", "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n <dict>\n <key>CFBundleDevelopmentRegion</key>\n <string>en</string>\n <key>CFBundleDocumentTypes</key>\n <dict>\n <key>SKAdNetworkItems</key>\n <dict />\n </dict>\n <key>CFBundleExecutable</key>\n <string>$(EXECUTABLE_NAME)</string>\n <key>CFBundleIdentifier</key>\n <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n <key>CFBundleInfoDictionaryVersion</key>\n <string>6.0</string>\n <key>CFBundleName</key>\n <string>$(PRODUCT_NAME)</string>\n <key>CFBundlePackageType</key>\n <string>BNDL</string>\n <key>CFBundleShortVersionString</key>\n <string>1.0</string>\n <key>CFBundleSignature</key>\n <string>????</string>\n <key>CFBundleVersion</key>\n <string>1</string>\n <key>NSAppTransportSecurity</key>\n <dict>\n <key>NSAllowsArbitraryLoads</key>\n <true />\n </dict>\n <key>SKAdNetworkItems</key>\n <array>\n <dict>\n <key>SKAdNetworkIdentifier</key>\n <string>4DZT52R2T5.skadnetwork</string>\n </dict>\n <dict>\n <key>SKAdNetworkIdentifier</key>\n <string>123456.skadnetwork</string>\n </dict>\n </array>\n </dict>\n</plist>\n")]
|
||||
public void WriteSkAdNetworkIdsToInfoPlist(string rootFolder, string expectedContents)
|
||||
{
|
||||
var ids = new HashSet<string> { "4DZT52R2T5.skadnetwork", "123456.skadnetwork" };
|
||||
PostProcessBuildPlist.WriteSkAdNetworkIdsToInfoPlist(ids, rootFolder);
|
||||
Assert.That(File.ReadAllText(rootFolder + "Info.plist"), Is.EqualTo(expectedContents), "Info.plist was not updated as expected");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("4DZT52R2T5.skadnetwork", true)]
|
||||
[TestCase("invalid.skadnetwork", false)]
|
||||
[TestCase("", false)]
|
||||
[TestCase(null, false)]
|
||||
public void PlistContainsAdNetworkId(string adNetworkId, bool expectedValue)
|
||||
{
|
||||
var plistArray = new PlistElementArray();
|
||||
plistArray.AddDict().SetString("SKAdNetworkIdentifier", "4DZT52R2T5.skadnetwork");
|
||||
Assert.That(PostProcessBuildPlist.PlistContainsAdNetworkId(plistArray, adNetworkId), Is.EqualTo(expectedValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9a7d8f7d4212542229d19c5bb4e3b06d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,57 @@
|
||||
#if UNITY_2018_1_OR_NEWER && UNITY_IOS
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.Advertisement.IosSupport.Editor.Tests
|
||||
{
|
||||
public class SkAdNetworkParserTests
|
||||
{
|
||||
[Test]
|
||||
[Category("WorksInIsolation")]
|
||||
[TestCase(SkAdNetworkFileExtension.XML)]
|
||||
[TestCase(SkAdNetworkFileExtension.JSON)]
|
||||
[TestCase(SkAdNetworkFileExtension.NONE)]
|
||||
public void ParserHandlesExtensionType(string parserType)
|
||||
{
|
||||
Assert.That(SkAdNetworkParser.GetParser(parserType).GetExtension(), Is.EqualTo(parserType), "GetExtension did not match the expected value");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(SkAdNetworkFileExtension.XML, "Assets/SkAdNetworks.xml", new[] {"4DZT52R2T5.skadnetwork", "123456.skadnetwork"})]
|
||||
[TestCase(SkAdNetworkFileExtension.JSON, "Assets/SkAdNetworks.json", new[] {"4DZT52R2T5.skadnetwork", "bvpn9ufa9b.skadnetwork"})]
|
||||
[TestCase(SkAdNetworkFileExtension.JSON, "Assets/AdditionalTestData/SkAdNetworks.json", new[] {"4FZDC2EVR5.skadnetwork", "V72QYCH5UU.skadnetwork"})]
|
||||
[TestCase(SkAdNetworkFileExtension.NONE, "Assets/SkAdNetworks", new[] {"yclnxrl5pm.skadnetwork","wg4vff78zm.skadnetwork","238da6jt44.skadnetwork","4pfyvq9l8r.skadnetwork","4468km3ulz.skadnetwork","m8dbw4sv7c.skadnetwork","wzmmz9fp6w.skadnetwork","zmvfpc5aq8.skadnetwork","5lm9lj6jb7.skadnetwork","mlmmfzh3r3.skadnetwork","8s468mfl3y.skadnetwork","44n7hlldy6.skadnetwork","5a6flpkh64.skadnetwork","2u9pt9hc89.skadnetwork","3rd42ekr43.skadnetwork","424m5254lk.skadnetwork","ppxm28t8ap.skadnetwork","v79kvwwj4g.skadnetwork","4fzdc2evr5.skadnetwork","cstr6suwn9.skadnetwork","3qy4746246.skadnetwork","bvpn9ufa9b.skadnetwork","9rd848q2bz.skadnetwork","f73kdq92p3.skadnetwork","ydx93a7ass.skadnetwork","44jx6755aq.skadnetwork","v72qych5uu.skadnetwork","glqzh8vgby.skadnetwork","hs6bdukanm.skadnetwork","prcb7njmu6.skadnetwork","c6k4g5qg8m.skadnetwork","3sh42y64q3.skadnetwork","578prtvx9j.skadnetwork","4dzt52r2t5.skadnetwork","7ug5zh24hu.skadnetwork","9t245vhmpl.skadnetwork","tl55sbb4fm.skadnetwork","22mmun2rn5.skadnetwork", "488r3q3dtq.skadnetwork","t38b2kh725.skadnetwork","f38h382jlk.skadnetwork","lr83yxwka7.skadnetwork","kbd757ywx3.skadnetwork","av6w8kgt66.skadnetwork","24t9a8vw3c.skadnetwork"})]
|
||||
public void ParserCanParseSourceAsExpected(string parserType, string sourceDataPath, string[] expectedResults) {
|
||||
var result = SkAdNetworkParser.GetParser(parserType).ParseSource(new SkAdNetworkLocalSource(sourceDataPath));
|
||||
Assert.That(result, Is.EquivalentTo(expectedResults), "Parser did not return the expected results");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(SkAdNetworkFileExtension.XML, "Assets/SkAdNetworks_Bad1.xml", new[] {"123456.skadnetwork"})] //Invalid Key
|
||||
[TestCase(SkAdNetworkFileExtension.JSON, "Assets/SkAdNetworks_Bad1.json", new[] {"bvpn9ufa9b.skadnetwork"})] //Invalid Key
|
||||
[TestCase(SkAdNetworkFileExtension.XML, "Assets/SkAdNetworks_Bad2.xml", new string[] {})] //Data format corrupted
|
||||
[TestCase(SkAdNetworkFileExtension.JSON, "Assets/SkAdNetworks_Bad2.json", new string[] {})] //Data format corrupted
|
||||
[TestCase(SkAdNetworkFileExtension.JSON, "Assets/SkAdNetworks_Bad", new string[] {})] //Invalid protocol
|
||||
[TestCase(SkAdNetworkFileExtension.JSON, "Assets/SkAdNetworks_Bad2", new string[] {})] //Invalid url
|
||||
[TestCase(SkAdNetworkFileExtension.JSON, "Assets/SkAdNetworks_Bad3", new string[] {})] //Valid url to Data in an invalid format
|
||||
public void ParserCanHandleInvalidFiles(string parserType, string sourceDataPath, string[] expectedResults)
|
||||
{
|
||||
Assert.That(SkAdNetworkParser.GetParser(parserType).ParseSource(new SkAdNetworkLocalSource(sourceDataPath)), Is.EquivalentTo(expectedResults), "Parser did not return the expected results");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Category("WorksInIsolation")]
|
||||
[TestCase("-1")]
|
||||
[TestCase(null)]
|
||||
[TestCase("a")]
|
||||
[TestCase("xmls")]
|
||||
[TestCase("xml*")]
|
||||
[TestCase("*xml")]
|
||||
[TestCase(".xml")]
|
||||
public void InvalidParserType(string parserType)
|
||||
{
|
||||
Assert.IsNull(SkAdNetworkParser.GetParser(parserType));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aaa756117fb2142798882ade06f4f9e0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,55 @@
|
||||
#if UNITY_2018_1_OR_NEWER && UNITY_IOS
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Unity.Advertisement.IosSupport.Editor.Tests
|
||||
{
|
||||
public class SkAdNetworkSourceTests
|
||||
{
|
||||
[Test]
|
||||
[Category("WorksInIsolation")]
|
||||
[TestCase("ExpectedPath/To/File")]
|
||||
public void LocalSourcePathSetOnCreate(string expectedPath)
|
||||
{
|
||||
Assert.That(new SkAdNetworkLocalSource(expectedPath).Path, Is.EqualTo(expectedPath), "Path was not properly set in constructor");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Category("WorksInIsolation")]
|
||||
[TestCase("ExpectedPath/To/File")]
|
||||
public void RemoteSourcePathSetOnCreate(string expectedPath)
|
||||
{
|
||||
Assert.That(new SkAdNetworkRemoteSource(expectedPath).Path, Is.EqualTo(expectedPath), "Path was not properly set in constructor");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("Assets/SkAdNetworks.json")]
|
||||
[TestCase("Assets/SkAdNetworks.xml")]
|
||||
[TestCase("Assets/SkAdNetworks")]
|
||||
public void LocalSourceCanOpenStream(string testFilePath)
|
||||
{
|
||||
Assert.NotNull(new SkAdNetworkLocalSource(testFilePath).Open(), "Unable to open stream");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("Assets/SkAdNetworksInvalidFilePath.json")]
|
||||
[TestCase("Assets/SkAdNetworksInvalidFilePath.xml")]
|
||||
[TestCase("Assets/SkAdNetworksInvalidFilePath")]
|
||||
public void LocalSourceInvalidFileThrowsException(string testFilePath)
|
||||
{
|
||||
Assert.Throws<FileNotFoundException>(() => new SkAdNetworkLocalSource(testFilePath).Open(), "FileNotFoundException should be thrown when the filepath is invalid");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Category("WorksInIsolation")]
|
||||
[TestCase(SkAdNetworkFileExtension.XML, 1)]
|
||||
[TestCase(SkAdNetworkFileExtension.JSON, 2)]
|
||||
[TestCase(SkAdNetworkFileExtension.NONE, 2)]
|
||||
public void LocalSourceProviderFindsExpectedFiles(string extension, int expectedCount)
|
||||
{
|
||||
Assert.That(new SkAdNetworkLocalSourceProvider().GetSources("SKAdNetworks", extension).Count(), Is.EqualTo(expectedCount), "GetSources() did not return the expected count");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b9698abccc22b4f979250ee7c80107b0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "Unity.Advertisement.IosSupport.Editor.Tests",
|
||||
"references": [
|
||||
"Unity.Advertisement.IosSupport",
|
||||
"Unity.Advertisement.IosSupport.Editor"
|
||||
],
|
||||
"optionalUnityReferences": [
|
||||
"TestAssemblies"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": []
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27574058f8bb942fe9dc91742aa31f4b
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 62717391892894f1180a615db8ad6314
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,17 @@
|
||||
using UnityEngine;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Unity.Advertisement.IosSupport.Tests
|
||||
{
|
||||
public class RuntimeTests
|
||||
{
|
||||
[Test]
|
||||
[Timeout(10000)]
|
||||
|
||||
//[UnityPlatform (exclude = new[] { RuntimePlatform.IPhonePlayer })] //Need to find a way to programatically set state on the iPhone for this app otherwise, even on iOS initial state will be Not Determined.
|
||||
public void TestTrackingStatusMessageUnsupported()
|
||||
{
|
||||
Assert.That(ATTrackingStatusBinding.GetAuthorizationTrackingStatus(), Is.EqualTo(ATTrackingStatusBinding.AuthorizationTrackingStatus.NOT_DETERMINED));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d467e3b930724e0ca757fb20c27323b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "Unity.Advertisement.IosSupport.Tests",
|
||||
"references": [
|
||||
"Unity.Advertisement.IosSupport"
|
||||
],
|
||||
"optionalUnityReferences": [
|
||||
"TestAssemblies"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor",
|
||||
"iOS"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": []
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa2578a81945d4cd8911322bab548f2a
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "com.unity.ads.ios-support",
|
||||
"displayName":"iOS 14 Advertising Support",
|
||||
"version": "1.2.0",
|
||||
"unity": "2018.4",
|
||||
"description": "Provides support for App Tracking Transparency and SkAdNetwork API newly introduced in Apple iOS 14.\n\nIncludes a sample implementation of a customizable context screen to show before requesting tracking permission.",
|
||||
"dependencies": {
|
||||
},
|
||||
"_upm": {
|
||||
"gameService": {
|
||||
"groupIndex": 4,
|
||||
"groupName": "Monetization"
|
||||
},
|
||||
"supportedPlatforms": [
|
||||
"iOS"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59f47ddbbfc5d4497b69fcaa8fd81356
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user