Skip to content
This repository has been archived by the owner on Jul 25, 2023. It is now read-only.

Commit

Permalink
Release 1.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Str4tos committed Mar 2, 2021
1 parent 2bc8335 commit 56ff01c
Show file tree
Hide file tree
Showing 13 changed files with 291 additions and 33 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Clever Ads Solutions Unity Plugin Change Log

## [1.2.0] - 2021-03-02
### Dependencies
- CleverAdsSolutions - [2.0.0](https://github.com/cleveradssolutions/CAS-Unity/releases)
### Features
- Added text localization in 15 languages.
- Added iOS [App Tracking Transparency request](https://developer.apple.com/documentation/apptrackingtransparency) in separated script `CASUAppTracking.m`.
- Sets `MobileAds.targetingOptions.age` on select user year of birth.
### Changes
- Deprecate `MobileAds.BuildManager().WithUserConsent()` no longer needs to be called.

## [1.1.4] - 2021-02-11
### Features
- Remove int parse from string in Audience Definition logic.
Expand Down
64 changes: 37 additions & 27 deletions Editor/ConsentRequestParametersEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public class ConsentRequestParametersEditor : Editor
private const string templateSettingsPrefabName = "NetworkPolicy.prefab";
private const string customUIPrefabName = "UserConsentUI.prefab";
private const string customSettingsPrefabName = "SettingToggleUI.prefab";
private const string configuringPrivacyURL = Utils.gitRootURL + "CAS-Unity#include-ios";
private const string locationUsageDefaultDescription = "Your data will be used to provide you a better and personalized ad experience.";


private SerializedProperty showInEditorProp;
private SerializedProperty withAudienceDefinitionProp;
Expand All @@ -30,6 +33,7 @@ public class ConsentRequestParametersEditor : Editor
private SerializedProperty settingsTogglePrefabProp;
private SerializedProperty privacyPolicyUrlProp;
private SerializedProperty termsOfUseUrlProp;
private SerializedProperty trackingUsageDescriptionProp;

private ReorderableList privacyPolicyList;
private ReorderableList termsOfUseList;
Expand All @@ -38,7 +42,6 @@ public class ConsentRequestParametersEditor : Editor

private string newCASVersion = null;
private bool allowedPackageUpdate = false;
private bool trackingDescriptionExist = false;

private void OnEnable()
{
Expand All @@ -52,6 +55,7 @@ private void OnEnable()
settingsTogglePrefabProp = props.FindProperty( "settingsTogglePrefab" );
privacyPolicyUrlProp = props.FindProperty( "privacyPolicyUrl" );
termsOfUseUrlProp = props.FindProperty( "termsOfUseUrl" );
trackingUsageDescriptionProp = props.FindProperty( "trackingUsageDescription" );

privacyPolicyList = new ReorderableList( props, privacyPolicyUrlProp, true, true, true, true )
{
Expand All @@ -71,10 +75,6 @@ private void OnEnable()

EditorApplication.delayCall +=
() => newCASVersion = Utils.GetNewVersionOrNull( gitRepoName, UserConsent.version, false );


var iosSettings = Utils.GetSettingsAsset( BuildTarget.iOS, false );
trackingDescriptionExist = iosSettings && !string.IsNullOrEmpty( iosSettings.defaultIOSTrakingUsageDescription );
}

public override void OnInspectorGUI()
Expand All @@ -85,22 +85,6 @@ public override void OnInspectorGUI()
Utils.LinksToolbarGUI( gitRepoName );

EditorGUILayout.PropertyField( withAudienceDefinitionProp );

EditorGUILayout.PropertyField( withRequestTrackingTransparencyProp );
EditorGUI.indentLevel++;
EditorGUILayout.HelpBox( "iOS App Tracking Transparency Request", MessageType.None );
EditorGUI.indentLevel--;
if (!trackingDescriptionExist && withRequestTrackingTransparencyProp.boolValue)
{
withRequestTrackingTransparencyProp.boolValue = false;
if (EditorUtility.DisplayDialog( "App Tracking Transparency request",
"Please set NSUserTrackingUsageDescription in 'Assets > CleverAdsSolutions > iOS Settings' menu to correct tracking authorization request.",
"Open iOS settings", "Disable request" ))
{
Utils.OpenIOSSettingsWindow();
}
}

EditorGUILayout.PropertyField( withDeclineOptionProp );
EditorGUILayout.PropertyField( showInEditorProp );
EditorGUILayout.Space();
Expand All @@ -118,17 +102,43 @@ public override void OnInspectorGUI()
uiPrefabProp, templateUIPrefabName, customUIPrefabName,
typeof( UserConsentUI ) );

CAS.UEditor.HelpStyles.BeginBoxScope();
EditorGUILayout.PropertyField( withMediationSettingsProp );
bool disableTogglePrefab = !withMediationSettingsProp.boolValue;
EditorGUI.BeginDisabledGroup( disableTogglePrefab );
HelpStyles.BeginBoxScope();
bool enableTogglePrefab = withMediationSettingsProp.boolValue;
if (enableTogglePrefab != EditorGUILayout.ToggleLeft( "With Mediaiton Settings", enableTogglePrefab ))
{
enableTogglePrefab = !enableTogglePrefab;
withMediationSettingsProp.boolValue = enableTogglePrefab;
}
EditorGUI.BeginDisabledGroup( !enableTogglePrefab );
DrawPrefabSelector( "Toggle UI Prefab",
settingsTogglePrefabProp, templateSettingsPrefabName, customSettingsPrefabName,
typeof( MediationPolicyUI ) );
EditorGUI.EndDisabledGroup();
if (disableTogglePrefab)
if (!enableTogglePrefab)
settingsTogglePrefabProp.objectReferenceValue = null;
CAS.UEditor.HelpStyles.EndBoxScope();
HelpStyles.EndBoxScope();

HelpStyles.BeginBoxScope();
var activeTracking = withRequestTrackingTransparencyProp.boolValue;
if (activeTracking != GUILayout.Toggle( activeTracking,
"With iOS App Tracking Transparency requeset" ))
{
activeTracking = !activeTracking;
withRequestTrackingTransparencyProp.boolValue = activeTracking;
}
EditorGUI.BeginDisabledGroup( !activeTracking );
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField( "Tracking Usage Description:" );
if (GUILayout.Button( "Default", EditorStyles.miniButton, GUILayout.ExpandWidth( false ) ))
trackingUsageDescriptionProp.stringValue = locationUsageDefaultDescription;
if (GUILayout.Button( "Info", EditorStyles.miniButton, GUILayout.ExpandWidth( false ) ))
Application.OpenURL( configuringPrivacyURL );
EditorGUILayout.EndHorizontal();
trackingUsageDescriptionProp.stringValue =
EditorGUILayout.TextArea( trackingUsageDescriptionProp.stringValue, HelpStyles.wordWrapTextAred );
EditorGUILayout.HelpBox( "NSUserTrackingUsageDescription key with a custom message describing your usage location tracking to AppTrackingTransparency.Request(). Can be empty if not using location tracking", MessageType.None );
EditorGUI.EndDisabledGroup();
HelpStyles.EndBoxScope();

obj.ApplyModifiedProperties();
}
Expand Down
29 changes: 29 additions & 0 deletions Editor/PostprocessiOSBuild.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#if UNITY_IOS || CASDeveloper
using System.IO;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;
using UnityEngine;

namespace CAS.UserConsent
{
internal class PostprocessiOSBuild
{
[PostProcessBuild]
public static void OnPostProcessBuild( BuildTarget buildTarget, string path )
{
if (buildTarget != BuildTarget.iOS)
return;
var parameters = UserConsent.BuildRequest();
var trakingUsage = parameters.defaultIOSTrakingUsageDescription;
if (string.IsNullOrEmpty( trakingUsage ))
return;
string plistPath = Path.Combine( path, "Info.plist" );
PlistDocument plist = new PlistDocument();
plist.ReadFromFile( plistPath );
plist.root.SetString( "NSUserTrackingUsageDescription", trakingUsage );
File.WriteAllText( plistPath, plist.WriteToString() );
}
}
}
#endif
11 changes: 11 additions & 0 deletions Editor/PostprocessiOSBuild.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Plugins.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Plugins/iOS.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions Plugins/iOS/CASUAppTracking.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// CASUAppTracking.m
// CASUnityPlugin
//
// Copyright © 2021 Clever Ads Solutions. All rights reserved.
//

#import <AppTrackingTransparency/AppTrackingTransparency.h>

typedef void (*CASUTrackingStatusCallback)(NSInteger status);

void CASURequestTracking(CASUTrackingStatusCallback callback)
{
if (@available(iOS 14, *)) {
[ATTrackingManager
requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
if (callback) {
callback((int)status);
}
}];
} else {
if (callback) {
callback(3);
}
}
}
39 changes: 39 additions & 0 deletions Plugins/iOS/CASUAppTracking.m.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

83 changes: 83 additions & 0 deletions Runtime/AppTrackingTransparency.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System;
using System.Runtime.InteropServices;

namespace CAS.iOS
{
/// <summary>
/// Wraps for the native iOS 14.0 ATTrackingManager.
/// A class that provides a tracking authorization request and the tracking authorization status of the app.
/// <see cref="https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager"/>
/// </summary>
public static class AppTrackingTransparency
{
public enum Status
{
NotDetermined,
Restricted,
Denied,
Authorized
}

/// <summary>
/// Returns information about your application’s tracking authorization status.
/// Users are able to grant or deny developers tracking privileges on a per-app basis.
/// Application developers must call <see cref="Request()"/> for the ability to track users.
///
/// The current authorization status. If the user has not yet been prompted to approve access, the return value will either be
/// <see cref="Status.NotDetermined"/>, or <see cref="Status.Restricted"/> if this value is managed.
/// Once the user has been prompted, the return value will be either <see cref="Status.Denied"/> or <see cref="Status.Authorized"/>.
/// </summary>
public static event Action<Status> OnAuthorizationRequestComplete;

/// <summary>
/// Request user tracking authorization with a completion handler returning the user's authorization status.
/// Users are able to grant or deny developers tracking privileges on a per-app basis.
/// This method allows developers to determine if access has been granted. On first use, this method will prompt the user to grant or deny access.
///
/// Please set <b>NSUserTrackingUsageDescription</b> in 'Assets > CleverAdsSolutions > iOS Settings' menu to correct tracking authorization request.
///
/// The completion handler will be called with the result of the user's decision for granting or denying permission to use application tracking.
/// The completion handler will be called immediately if access to request authorization is restricted.
/// The completion handler will be called immediately if runtime platform is not iOS 14 or newer.
/// </summary>
/// <exception cref="ArgumentNullException">Please subscribe callback OnAuthorizationRequestComplete before call Request()</exception>
/// <exception cref="ArgumentException">Please set NSUserTrackingUsageDescription in 'Assets > CleverAdsSolutions > iOS Settings' menu to correct tracking authorization request.</exception>
public static void Request()
{
if (OnAuthorizationRequestComplete == null)
throw new ArgumentNullException( "Please subscribe callback OnAuthorizationRequestComplete before call Request()." );
#if UNITY_IOS || CASDeveloper
#if UNITY_EDITOR
var settings = UserConsent.UserConsent.BuildRequest();
if (string.IsNullOrEmpty( settings.defaultIOSTrakingUsageDescription ))
throw new ArgumentNullException(
"Please set NSUserTrackingUsageDescription in 'Assets > CleverAdsSolutions > Consent Request parameters' menu to correct tracking authorization request." );
#endif
CASURequestTracking( AuthorizationRequestComplete );
#else
OnAuthorizationRequestComplete( Status.Authorized );
#endif
}

#if UNITY_IOS || CASDeveloper
internal delegate void CASUTrackingStatusCallback( int status );

[DllImport( "__Internal" )]
internal static extern void CASURequestTracking( CASUTrackingStatusCallback callback );

[AOT.MonoPInvokeCallback( typeof( CASUTrackingStatusCallback ) )]
private static void AuthorizationRequestComplete( int status )
{
try
{
if (OnAuthorizationRequestComplete != null)
OnAuthorizationRequestComplete( ( Status )status );
}
catch (Exception e)
{
UnityEngine.Debug.LogException( e );
}
}
#endif
}
}
13 changes: 13 additions & 0 deletions Runtime/AppTrackingTransparency.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 17 additions & 4 deletions Runtime/ConsentClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,18 @@ internal static int GetYearOfBirth()
internal static Audience SetYearOfBirth( int year )
{
PlayerPrefs.SetInt( yearOfBirthPref, year );
var result = GetAudience( year );
MobileAds.settings.taggedAudience = result;
return result;
if (year < 0)
MobileAds.settings.taggedAudience = Audience.Mixed;
else
{
var age = DateTime.Now.Year - year;
if (age < 12)
MobileAds.settings.taggedAudience = Audience.Children;
else
MobileAds.settings.taggedAudience = Audience.NotChildren;
MobileAds.targetingOptions.age = age;
}
return MobileAds.settings.taggedAudience;
}

internal static Audience GetAudience( int year )
Expand Down Expand Up @@ -86,9 +95,13 @@ internal static UserConsentUI Request( ConsentRequestParameters parameters )
Audience savedAudience = Audience.Mixed;
if (parameters.withAudienceDefinition && parameters.resetStatus < 2)
{
savedAudience = GetAudience( GetYearOfBirth() );
int selectedYear = GetYearOfBirth();
savedAudience = GetAudience( selectedYear );
if (savedAudience != Audience.Mixed)
MobileAds.settings.taggedAudience = savedAudience;

if (selectedYear > 0)
MobileAds.targetingOptions.age = DateTime.Now.Year - selectedYear;
}

if (parameters.resetStatus == 0 || savedAudience == Audience.Children)
Expand Down
Loading

0 comments on commit 56ff01c

Please sign in to comment.