nccgs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/nccgs-accessibility-specialist.md +26 -0
- package/.claude/agents/nccgs-adversarial-reviewer.md +26 -0
- package/.claude/agents/nccgs-ai-programmer.md +26 -0
- package/.claude/agents/nccgs-analytics-engineer.md +26 -0
- package/.claude/agents/nccgs-art-direction-lead.md +26 -0
- package/.claude/agents/nccgs-audio-direction-lead.md +26 -0
- package/.claude/agents/nccgs-creative-director.md +26 -0
- package/.claude/agents/nccgs-documentation-manager.md +26 -0
- package/.claude/agents/nccgs-economy-designer.md +26 -0
- package/.claude/agents/nccgs-engine-programmer.md +26 -0
- package/.claude/agents/nccgs-game-design-lead.md +26 -0
- package/.claude/agents/nccgs-game-designer.md +26 -0
- package/.claude/agents/nccgs-gameplay-programmer.md +26 -0
- package/.claude/agents/nccgs-level-designer.md +26 -0
- package/.claude/agents/nccgs-live-ops-designer.md +26 -0
- package/.claude/agents/nccgs-localization-lead.md +26 -0
- package/.claude/agents/nccgs-narrative-lead.md +26 -0
- package/.claude/agents/nccgs-network-programmer.md +26 -0
- package/.claude/agents/nccgs-performance-analyst.md +26 -0
- package/.claude/agents/nccgs-producer.md +26 -0
- package/.claude/agents/nccgs-production-coordinator.md +23 -0
- package/.claude/agents/nccgs-programming-lead.md +26 -0
- package/.claude/agents/nccgs-prototyper.md +26 -0
- package/.claude/agents/nccgs-qa-engineer.md +26 -0
- package/.claude/agents/nccgs-qa-lead.md +26 -0
- package/.claude/agents/nccgs-release-engineer.md +26 -0
- package/.claude/agents/nccgs-release-lead.md +26 -0
- package/.claude/agents/nccgs-security-engineer.md +26 -0
- package/.claude/agents/nccgs-sound-designer.md +26 -0
- package/.claude/agents/nccgs-systems-designer.md +26 -0
- package/.claude/agents/nccgs-technical-architect.md +26 -0
- package/.claude/agents/nccgs-technical-artist.md +26 -0
- package/.claude/agents/nccgs-technical-director.md +26 -0
- package/.claude/agents/nccgs-tools-programmer.md +26 -0
- package/.claude/agents/nccgs-ui-programmer.md +26 -0
- package/.claude/agents/nccgs-unity-build-specialist.md +26 -0
- package/.claude/agents/nccgs-unity-content-specialist.md +26 -0
- package/.claude/agents/nccgs-unity-implementer.md +26 -0
- package/.claude/agents/nccgs-unity-rendering-specialist.md +26 -0
- package/.claude/agents/nccgs-unity-systems-specialist.md +26 -0
- package/.claude/agents/nccgs-unity-ui-specialist.md +26 -0
- package/.claude/agents/nccgs-ux-designer.md +26 -0
- package/.claude/agents/nccgs-verification-engineer.md +26 -0
- package/.claude/agents/nccgs-world-builder.md +26 -0
- package/.claude/agents/nccgs-writer.md +26 -0
- package/.claude/nccgs/THIRD_PARTY_NOTICES.md +13 -0
- package/.claude/nccgs/VERSION +1 -0
- package/.claude/nccgs/constitution.md +131 -0
- package/.claude/nccgs/hooks/agent-audit.mjs +10 -0
- package/.claude/nccgs/hooks/common.mjs +41 -0
- package/.claude/nccgs/hooks/post-compact.mjs +1 -0
- package/.claude/nccgs/hooks/pre-compact.mjs +8 -0
- package/.claude/nccgs/hooks/protect-git.mjs +22 -0
- package/.claude/nccgs/hooks/protect-write.mjs +17 -0
- package/.claude/nccgs/hooks/session-start.mjs +15 -0
- package/.claude/nccgs/hooks/session-stop.mjs +7 -0
- package/.claude/nccgs/protocols/agent-contract.md +34 -0
- package/.claude/nccgs/protocols/context-packets.md +13 -0
- package/.claude/nccgs/protocols/evidence.md +15 -0
- package/.claude/nccgs/protocols/model-routing.md +22 -0
- package/.claude/nccgs/protocols/orchestration.md +26 -0
- package/.claude/nccgs/protocols/unity-boundary.md +11 -0
- package/.claude/nccgs/settings.fragment.json +77 -0
- package/.claude/nccgs/studio.json +347 -0
- package/.claude/nccgs/tools/configure-models.mjs +39 -0
- package/.claude/nccgs/unity-skills-manifest.json +727 -0
- package/.claude/nccgs/workflow-catalog.json +317 -0
- package/.claude/rules/nccgs-canonical-docs.md +19 -0
- package/.claude/rules/nccgs-editor-tools.md +12 -0
- package/.claude/rules/nccgs-localization.md +12 -0
- package/.claude/rules/nccgs-networking.md +13 -0
- package/.claude/rules/nccgs-performance.md +14 -0
- package/.claude/rules/nccgs-rendering.md +16 -0
- package/.claude/rules/nccgs-security.md +13 -0
- package/.claude/rules/nccgs-tests.md +18 -0
- package/.claude/rules/nccgs-ui.md +14 -0
- package/.claude/rules/nccgs-unity-assets.md +21 -0
- package/.claude/rules/nccgs-unity-code.md +22 -0
- package/.claude/skills/accessibility-review/SKILL.md +14 -0
- package/.claude/skills/architecture-decision/SKILL.md +14 -0
- package/.claude/skills/asset-audit/SKILL.md +14 -0
- package/.claude/skills/audit/SKILL.md +16 -0
- package/.claude/skills/audit/references/dimensions.md +46 -0
- package/.claude/skills/balance-review/SKILL.md +14 -0
- package/.claude/skills/bug-triage/SKILL.md +14 -0
- package/.claude/skills/build-live-game/SKILL.md +317 -0
- package/.claude/skills/build-live-game/references/achievements.md +779 -0
- package/.claude/skills/build-live-game/references/apis.md +280 -0
- package/.claude/skills/build-live-game/references/authentication.md +437 -0
- package/.claude/skills/build-live-game/references/battlepass.md +860 -0
- package/.claude/skills/build-live-game/references/cloud-code.md +563 -0
- package/.claude/skills/build-live-game/references/cloud-save.md +474 -0
- package/.claude/skills/build-live-game/references/deployment.md +216 -0
- package/.claude/skills/build-live-game/references/player-account.md +813 -0
- package/.claude/skills/build-live-game/references/remote-config.md +96 -0
- package/.claude/skills/build-live-game/references/tooling.md +431 -0
- package/.claude/skills/closure/SKILL.md +14 -0
- package/.claude/skills/code-review/SKILL.md +14 -0
- package/.claude/skills/compatibility-review/SKILL.md +14 -0
- package/.claude/skills/context-pack/SKILL.md +14 -0
- package/.claude/skills/dependency-review/SKILL.md +14 -0
- package/.claude/skills/design/SKILL.md +20 -0
- package/.claude/skills/design-review/SKILL.md +14 -0
- package/.claude/skills/evidence-review/SKILL.md +14 -0
- package/.claude/skills/hotfix/SKILL.md +14 -0
- package/.claude/skills/implement-in-app-purchases/README.md +233 -0
- package/.claude/skills/implement-in-app-purchases/SKILL.md +158 -0
- package/.claude/skills/implement-in-app-purchases/references/api-notes.md +562 -0
- package/.claude/skills/implement-in-app-purchases/references/codeless-catalog.md +331 -0
- package/.claude/skills/implement-in-app-purchases/references/convert-adapty.md +268 -0
- package/.claude/skills/implement-in-app-purchases/references/convert-essentialkit.md +239 -0
- package/.claude/skills/implement-in-app-purchases/references/convert-revenuecat.md +275 -0
- package/.claude/skills/implement-in-app-purchases/references/convert-unipay.md +145 -0
- package/.claude/skills/implement-in-app-purchases/references/migration-v4-to-v5.md +204 -0
- package/.claude/skills/implement-in-app-purchases/references/path-add-iap-to-new-project.md +198 -0
- package/.claude/skills/implement-in-app-purchases/references/path-convert-native-google-billing.md +356 -0
- package/.claude/skills/implement-in-app-purchases/references/path-convert-native-storekit.md +446 -0
- package/.claude/skills/implement-in-app-purchases/references/path-implement-iap-d2c.md +680 -0
- package/.claude/skills/implement-in-app-purchases/references/platform-notes.md +204 -0
- package/.claude/skills/implement-in-app-purchases/references/pre-check.md +205 -0
- package/.claude/skills/incident-recovery/SKILL.md +14 -0
- package/.claude/skills/initialize-ai-navigation/SKILL.md +95 -0
- package/.claude/skills/initialize-ai-navigation/references/navigation-system.md +794 -0
- package/.claude/skills/levelplay-unity-integration/CHANGELOG.md +57 -0
- package/.claude/skills/levelplay-unity-integration/README.md +74 -0
- package/.claude/skills/levelplay-unity-integration/SKILL.md +1126 -0
- package/.claude/skills/levelplay-unity-integration/references/banner-api.md +920 -0
- package/.claude/skills/levelplay-unity-integration/references/best-practices.md +536 -0
- package/.claude/skills/levelplay-unity-integration/references/ilrd-api.md +337 -0
- package/.claude/skills/levelplay-unity-integration/references/initialization-api.md +630 -0
- package/.claude/skills/levelplay-unity-integration/references/interstitial-api.md +899 -0
- package/.claude/skills/levelplay-unity-integration/references/ios-setup.md +491 -0
- package/.claude/skills/levelplay-unity-integration/references/migration-sdk-9.md +666 -0
- package/.claude/skills/levelplay-unity-integration/references/privacy-settings.md +608 -0
- package/.claude/skills/levelplay-unity-integration/references/rewarded-api.md +902 -0
- package/.claude/skills/localization/SKILL.md +135 -0
- package/.claude/skills/localization/references/api-notes.md +76 -0
- package/.claude/skills/localization/resources/L10nBatchProcessor.cs +69 -0
- package/.claude/skills/localization/resources/LocalizedFontAsset.cs +18 -0
- package/.claude/skills/localize-game/SKILL.md +14 -0
- package/.claude/skills/migrate-project/SKILL.md +21 -0
- package/.claude/skills/migrate-project/references/procedure.md +63 -0
- package/.claude/skills/milestone-review/SKILL.md +14 -0
- package/.claude/skills/new-unity-project/SKILL.md +179 -0
- package/.claude/skills/optimize-audio/SKILL.md +199 -0
- package/.claude/skills/optimize-audio/resources/audio-import-api.md +146 -0
- package/.claude/skills/optimize-audio/resources/platform-settings.md +48 -0
- package/.claude/skills/optimize-text-mesh-pro/SKILL.md +182 -0
- package/.claude/skills/optimize-web/SKILL.md +393 -0
- package/.claude/skills/optimize-web/resources/WebOptimizer.cs +21 -0
- package/.claude/skills/optimize-web/resources/toktx-examples.sh +11 -0
- package/.claude/skills/performance-audit/SKILL.md +14 -0
- package/.claude/skills/physics-3d-collision/SKILL.md +442 -0
- package/.claude/skills/physics-3d-collision/references/troubleshooting.md +41 -0
- package/.claude/skills/physics-3d-collision/resources/CollisionDebugger.cs +33 -0
- package/.claude/skills/plan-feature/SKILL.md +14 -0
- package/.claude/skills/playtest/SKILL.md +14 -0
- package/.claude/skills/project-stage/SKILL.md +14 -0
- package/.claude/skills/prototype-feature/SKILL.md +14 -0
- package/.claude/skills/qa-plan/SKILL.md +14 -0
- package/.claude/skills/release/SKILL.md +18 -0
- package/.claude/skills/release-readiness/SKILL.md +14 -0
- package/.claude/skills/retrospective/SKILL.md +14 -0
- package/.claude/skills/review/SKILL.md +16 -0
- package/.claude/skills/security-audit/SKILL.md +14 -0
- package/.claude/skills/setup-multiplayer-services/SKILL.md +39 -0
- package/.claude/skills/setup-multiplayer-services/references/dgs-entrypoint.md +79 -0
- package/.claude/skills/setup-multiplayer-services/references/entrypoints.md +213 -0
- package/.claude/skills/setup-multiplayer-services/references/examples.md +33 -0
- package/.claude/skills/setup-multiplayer-services/references/implementation-fit.md +30 -0
- package/.claude/skills/setup-multiplayer-services/references/underlying-services.md +11 -0
- package/.claude/skills/setup-multiplayer-services/references/workflows-prerequisites.md +17 -0
- package/.claude/skills/setup-vivox-voice-chat/SKILL.md +118 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/.env.example +6 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/README.md +101 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/promptfooconfig.yaml +32 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/tests/init-and-login.yaml +76 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/tests/text-chat.yaml +65 -0
- package/.claude/skills/setup-vivox-voice-chat/evals/tests/voice-channels.yaml +74 -0
- package/.claude/skills/setup-vivox-voice-chat/references/events-and-participants.md +79 -0
- package/.claude/skills/setup-vivox-voice-chat/references/init-and-login.md +92 -0
- package/.claude/skills/setup-vivox-voice-chat/references/text-chat.md +93 -0
- package/.claude/skills/setup-vivox-voice-chat/references/troubleshooting.md +47 -0
- package/.claude/skills/setup-vivox-voice-chat/references/voice-channels.md +90 -0
- package/.claude/skills/shader-graph-create-custom-node/SKILL.md +25 -0
- package/.claude/skills/shader-graph-create-custom-node/resources/all_hints.hlsl +182 -0
- package/.claude/skills/sprint-plan/SKILL.md +14 -0
- package/.claude/skills/sprite-editor/SKILL.md +66 -0
- package/.claude/skills/sprite-editor/references/api_reference.md +151 -0
- package/.claude/skills/sprite-editor/references/background.md +112 -0
- package/.claude/skills/sprite-editor/references/templates.md +72 -0
- package/.claude/skills/sprite-editor/scripts/AutomaticSliceTexture.cs +40 -0
- package/.claude/skills/sprite-editor/scripts/GenerateNewSpriteRects.cs +200 -0
- package/.claude/skills/sprite-editor/scripts/GetTextureSourceImageSize.cs +32 -0
- package/.claude/skills/sprite-editor/scripts/GetTextureToSlice.cs +55 -0
- package/.claude/skills/sprite-editor/scripts/GridSliceTexture.cs +40 -0
- package/.claude/skills/sprite-editor/scripts/IsometricSliceTexture.cs +141 -0
- package/.claude/skills/sprite-editor/scripts/README.md +134 -0
- package/.claude/skills/sprite-editor/scripts/SetPivotExample.cs +58 -0
- package/.claude/skills/sprite-editor/scripts/SpriteToPng.cs +88 -0
- package/.claude/skills/status/SKILL.md +16 -0
- package/.claude/skills/story-readiness/SKILL.md +14 -0
- package/.claude/skills/test/SKILL.md +16 -0
- package/.claude/skills/ui/SKILL.md +142 -0
- package/.claude/skills/ui-imgui/SKILL.md +186 -0
- package/.claude/skills/ui-imgui/references/gui-elements.md +156 -0
- package/.claude/skills/ui-imgui/references/templates.md +141 -0
- package/.claude/skills/ui-review/SKILL.md +14 -0
- package/.claude/skills/ui-ugui/SKILL.md +282 -0
- package/.claude/skills/ui-ugui/references/scrollview-setup.md +29 -0
- package/.claude/skills/ui-uitk/SKILL.md +235 -0
- package/.claude/skills/ui-uitk/references/common-issues.md +74 -0
- package/.claude/skills/ui-uitk/references/custom-elements.md +241 -0
- package/.claude/skills/ui-uitk/references/painter2d.md +282 -0
- package/.claude/skills/ui-uitk/references/pointermanipulator-guide.md +94 -0
- package/.claude/skills/ui-uitk/references/svg-icons.md +136 -0
- package/.claude/skills/ui-uitk/references/ui-runtime-binding.md +234 -0
- package/.claude/skills/ui-uitk/references/uss-guide.md +138 -0
- package/.claude/skills/unity-cli/CHANGELOG.md +233 -0
- package/.claude/skills/unity-cli/SECURITY.md +22 -0
- package/.claude/skills/unity-cli/SKILL.md +414 -0
- package/.claude/skills/unity-cli/references/auth-license-cloud.md +146 -0
- package/.claude/skills/unity-cli/references/build-run-test.md +349 -0
- package/.claude/skills/unity-cli/references/collaboration.md +472 -0
- package/.claude/skills/unity-cli/references/config-hub.md +103 -0
- package/.claude/skills/unity-cli/references/diagnostics-maintenance.md +326 -0
- package/.claude/skills/unity-cli/references/editors-install.md +327 -0
- package/.claude/skills/unity-cli/references/integration-advanced.md +472 -0
- package/.claude/skills/unity-cli/references/projects-templates.md +574 -0
- package/.claude/skills/unity-package-management/SKILL.md +304 -0
- package/.claude/skills/unity-package-management/references/select-packages.md +108 -0
- package/.claude/skills/urp-postprocessing/SKILL.md +188 -0
- package/.claude/skills/urp-postprocessing/references/code-templates.md +119 -0
- package/.claude/skills/urp-postprocessing/references/effect-reference.md +86 -0
- package/.claude/skills/validate-urp-render-graph-renderer-feature/SKILL.md +269 -0
- package/.claude/skills/work/SKILL.md +36 -0
- package/.claude/skills/work/references/classification.md +41 -0
- package/.claude/skills/work/references/closure.md +50 -0
- package/.claude/skills/work/references/feature-contracts.md +32 -0
- package/.claude/skills/work/references/verification.md +26 -0
- package/CLAUDE.md +6 -0
- package/LICENSE +21 -0
- package/README.md +162 -0
- package/THIRD_PARTY_NOTICES.md +23 -0
- package/UPGRADING.md +32 -0
- package/VERSION +1 -0
- package/docs/ARCHITECTURE.md +73 -0
- package/docs/HUONG-DAN-MIGRATE-VA-SU-DUNG.md +324 -0
- package/docs/MIGRATION-MATRIX.md +23 -0
- package/docs/PROJECT-POLICY.md +67 -0
- package/docs/WORKFLOWS.md +61 -0
- package/package-assets/setup-vivox-voice-chat-evals.gitignore +7 -0
- package/package.json +41 -0
- package/scaffold/.nccgs/bugs/.gitkeep +1 -0
- package/scaffold/.nccgs/closures/.gitkeep +1 -0
- package/scaffold/.nccgs/context/.gitkeep +1 -0
- package/scaffold/.nccgs/decisions/.gitkeep +1 -0
- package/scaffold/.nccgs/evidence/.gitkeep +1 -0
- package/scaffold/.nccgs/features/.gitkeep +1 -0
- package/scaffold/.nccgs/migrations/.gitkeep +1 -0
- package/scaffold/.nccgs/playtests/.gitkeep +1 -0
- package/scaffold/.nccgs/project.yaml +103 -0
- package/scaffold/.nccgs/requirements.yaml +10 -0
- package/scaffold/.nccgs/reviews/.gitkeep +1 -0
- package/scaffold/.nccgs/state.md +40 -0
- package/scaffold/.nccgs/templates/agent-handoff.md +25 -0
- package/scaffold/.nccgs/templates/architecture-decision.md +27 -0
- package/scaffold/.nccgs/templates/closure-record.md +51 -0
- package/scaffold/.nccgs/templates/context-packet.yaml +17 -0
- package/scaffold/.nccgs/templates/evidence-record.md +23 -0
- package/scaffold/.nccgs/templates/feature-contract.md +35 -0
- package/scaffold/.nccgs/templates/migration-plan.md +40 -0
- package/scaffold/.nccgs/templates/waiver.md +11 -0
- package/scripts/cli.mjs +56 -0
- package/scripts/install.mjs +267 -0
- package/scripts/sync-unity-skills.mjs +126 -0
- package/scripts/validate.mjs +205 -0
- package/tests/framework.test.mjs +121 -0
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
# iOS-Specific Setup for LevelPlay
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
- [Overview](#overview)
|
|
5
|
+
- [Prerequisites](#prerequisites)
|
|
6
|
+
- [SKAdNetwork Configuration](#skadnetwork-configuration)
|
|
7
|
+
- [App Tracking Transparency (ATT)](#app-tracking-transparency-att)
|
|
8
|
+
- [Privacy Manifest](#privacy-manifest)
|
|
9
|
+
- [Xcode Build Settings](#xcode-build-settings)
|
|
10
|
+
- [Testing on iOS](#testing-on-ios)
|
|
11
|
+
- [Common iOS Issues](#common-ios-issues)
|
|
12
|
+
- [iOS Privacy Checklist](#ios-privacy-checklist)
|
|
13
|
+
- [Version-Specific Notes](#version-specific-notes)
|
|
14
|
+
- [Best Practices](#best-practices)
|
|
15
|
+
|
|
16
|
+
## Overview
|
|
17
|
+
|
|
18
|
+
LevelPlay SDK on iOS requires additional configuration beyond the basic Unity integration. This guide covers iOS-specific setup, including SKAdNetwork, App Tracking Transparency (ATT), and privacy manifest requirements.
|
|
19
|
+
|
|
20
|
+
## Prerequisites
|
|
21
|
+
|
|
22
|
+
For the current supported Unity, iOS deployment target, and Xcode versions, see the [LevelPlay iOS SDK integration guide](https://docs.unity.com/en-us/grow/levelplay/sdk/ios/sdk-integration).
|
|
23
|
+
|
|
24
|
+
## SKAdNetwork Configuration
|
|
25
|
+
|
|
26
|
+
### What is SKAdNetwork?
|
|
27
|
+
|
|
28
|
+
SKAdNetwork is Apple's privacy-preserving ad attribution framework. It allows advertisers to measure campaign effectiveness without accessing user-level data.
|
|
29
|
+
|
|
30
|
+
### Setup Steps
|
|
31
|
+
|
|
32
|
+
LevelPlay SDK automatically includes the required SKAdNetwork IDs in your app's Info.plist during the build process. However, you should verify this after building:
|
|
33
|
+
|
|
34
|
+
1. Build your Unity project for iOS
|
|
35
|
+
2. Open the generated Xcode project
|
|
36
|
+
3. Check `Info.plist` for the `SKAdNetworkItems` array
|
|
37
|
+
4. Verify it contains multiple SKAdNetwork IDs (format: `XXXX1234abc.skadnetwork`)
|
|
38
|
+
|
|
39
|
+
**If SKAdNetwork IDs are missing:**
|
|
40
|
+
|
|
41
|
+
The LevelPlay Unity Package should handle this automatically. If you notice missing IDs:
|
|
42
|
+
- Ensure you're using the latest LevelPlay Unity Package version
|
|
43
|
+
- Check the Unity console for any import warnings
|
|
44
|
+
- Manually add the SKAdNetwork IDs if necessary (see Unity documentation)
|
|
45
|
+
|
|
46
|
+
### Verifying SKAdNetwork Setup
|
|
47
|
+
|
|
48
|
+
After building to Xcode, you should see entries like this in Info.plist:
|
|
49
|
+
|
|
50
|
+
```xml
|
|
51
|
+
<key>SKAdNetworkItems</key>
|
|
52
|
+
<array>
|
|
53
|
+
<dict>
|
|
54
|
+
<key>SKAdNetworkIdentifier</key>
|
|
55
|
+
<string>cstr6suwn9.skadnetwork</string>
|
|
56
|
+
</dict>
|
|
57
|
+
<dict>
|
|
58
|
+
<key>SKAdNetworkIdentifier</key>
|
|
59
|
+
<string>4fzdc2evr5.skadnetwork</string>
|
|
60
|
+
</dict>
|
|
61
|
+
<!-- Many more entries... -->
|
|
62
|
+
</array>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## App Tracking Transparency (ATT)
|
|
66
|
+
|
|
67
|
+
### What is ATT?
|
|
68
|
+
|
|
69
|
+
Apple requires ATT authorization before your app tracks users or accesses the device's advertising identifier on iOS 14.5+. Request ATT authorization before calling `LevelPlay.Init()` — this is both an Apple platform requirement and necessary for personalized ads (which also affects fill rate).
|
|
70
|
+
|
|
71
|
+
### Implementation
|
|
72
|
+
|
|
73
|
+
ATT requires two parts: a post-build script that writes the permission description string into `Info.plist`, and a native plugin that performs the actual permission request.
|
|
74
|
+
|
|
75
|
+
### Part 1: Permission Description (Post-Build Script)
|
|
76
|
+
|
|
77
|
+
Apple requires a user-facing description explaining why your app requests tracking permission. Add it via a post-build script — this is the reliable approach across all Unity versions. The **User Tracking Usage Description** field in Player Settings is not present in Unity 6.
|
|
78
|
+
|
|
79
|
+
Create `Assets/Editor/iOSPostBuild.cs`:
|
|
80
|
+
|
|
81
|
+
```csharp
|
|
82
|
+
using UnityEngine;
|
|
83
|
+
using UnityEditor;
|
|
84
|
+
using UnityEditor.Callbacks;
|
|
85
|
+
|
|
86
|
+
#if UNITY_IOS
|
|
87
|
+
using UnityEditor.iOS.Xcode;
|
|
88
|
+
using System.IO;
|
|
89
|
+
#endif
|
|
90
|
+
|
|
91
|
+
public class iOSPostBuild
|
|
92
|
+
{
|
|
93
|
+
#if UNITY_IOS
|
|
94
|
+
[PostProcessBuild(999)]
|
|
95
|
+
public static void OnPostProcessBuild(BuildTarget target, string buildPath)
|
|
96
|
+
{
|
|
97
|
+
if (target != BuildTarget.iOS) return;
|
|
98
|
+
|
|
99
|
+
var plistPath = Path.Combine(buildPath, "Info.plist");
|
|
100
|
+
var plist = new PlistDocument();
|
|
101
|
+
plist.ReadFromFile(plistPath);
|
|
102
|
+
|
|
103
|
+
// Required for ATT prompt — shown to users in the system dialog
|
|
104
|
+
plist.root.SetString(
|
|
105
|
+
"NSUserTrackingUsageDescription",
|
|
106
|
+
"We use tracking to show you relevant ads and support free gameplay."
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
plist.WriteToFile(plistPath);
|
|
110
|
+
Debug.Log("iOSPostBuild: NSUserTrackingUsageDescription added to Info.plist");
|
|
111
|
+
}
|
|
112
|
+
#endif
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Customise the description** to match your app's purpose. Apple reviews this text and may reject vague descriptions.
|
|
117
|
+
|
|
118
|
+
### Part 2: Native Plugin for the Permission Request
|
|
119
|
+
|
|
120
|
+
Create `Assets/Plugins/iOS/ATTRequester.mm`:
|
|
121
|
+
|
|
122
|
+
```objc
|
|
123
|
+
#import <AppTrackingTransparency/AppTrackingTransparency.h>
|
|
124
|
+
|
|
125
|
+
typedef void (*ATTCallback)(int status);
|
|
126
|
+
|
|
127
|
+
extern "C"
|
|
128
|
+
{
|
|
129
|
+
// Returns current ATT status without prompting:
|
|
130
|
+
// 0 = Not Determined, 1 = Restricted, 2 = Denied, 3 = Authorized
|
|
131
|
+
int _ATT_GetStatus()
|
|
132
|
+
{
|
|
133
|
+
if (@available(iOS 14, *))
|
|
134
|
+
{
|
|
135
|
+
return (int)[ATTrackingManager trackingAuthorizationStatus];
|
|
136
|
+
}
|
|
137
|
+
return 3; // Pre-iOS 14: treat as Authorized
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Requests ATT permission and invokes callback with the resulting status.
|
|
141
|
+
// On pre-iOS 14 devices, immediately calls back with Authorized (3).
|
|
142
|
+
void _ATT_RequestPermission(ATTCallback callback)
|
|
143
|
+
{
|
|
144
|
+
if (@available(iOS 14, *))
|
|
145
|
+
{
|
|
146
|
+
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status)
|
|
147
|
+
{
|
|
148
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
149
|
+
if (callback) callback((int)status);
|
|
150
|
+
});
|
|
151
|
+
}];
|
|
152
|
+
}
|
|
153
|
+
else
|
|
154
|
+
{
|
|
155
|
+
if (callback) callback(3);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Note:** `dispatch_async(dispatch_get_main_queue(), ...)` returns the callback to Unity's main thread, which is required for safe IL2CPP interop.
|
|
162
|
+
|
|
163
|
+
### Part 3: Integrating ATT into LevelPlayInitializer
|
|
164
|
+
|
|
165
|
+
ATT must complete before `LevelPlay.Init()`. Modify your `LevelPlayInitializer.cs` from Step 7 to use a coroutine `Start()`:
|
|
166
|
+
|
|
167
|
+
```csharp
|
|
168
|
+
using System.Collections;
|
|
169
|
+
using System.Runtime.InteropServices;
|
|
170
|
+
using UnityEngine;
|
|
171
|
+
using Unity.Services.LevelPlay;
|
|
172
|
+
|
|
173
|
+
public class LevelPlayInitializer : MonoBehaviour
|
|
174
|
+
{
|
|
175
|
+
[SerializeField] private string appKey;
|
|
176
|
+
|
|
177
|
+
#if UNITY_IOS && !UNITY_EDITOR
|
|
178
|
+
private delegate void ATTCallbackDelegate(int status);
|
|
179
|
+
|
|
180
|
+
[DllImport("__Internal")] private static extern int _ATT_GetStatus();
|
|
181
|
+
[DllImport("__Internal")] private static extern void _ATT_RequestPermission(ATTCallbackDelegate callback);
|
|
182
|
+
|
|
183
|
+
private const int ATT_NOT_DETERMINED = 0;
|
|
184
|
+
private static bool _attDone = false;
|
|
185
|
+
|
|
186
|
+
[AOT.MonoPInvokeCallback(typeof(ATTCallbackDelegate))]
|
|
187
|
+
private static void OnATTCallback(int status)
|
|
188
|
+
{
|
|
189
|
+
Debug.Log($"ATT: user responded — status {status}");
|
|
190
|
+
_attDone = true;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
private IEnumerator RequestATT()
|
|
194
|
+
{
|
|
195
|
+
// Skip prompt if user has already responded (e.g. returning user)
|
|
196
|
+
if (_ATT_GetStatus() != ATT_NOT_DETERMINED)
|
|
197
|
+
{
|
|
198
|
+
Debug.Log($"ATT: already determined (status {_ATT_GetStatus()})");
|
|
199
|
+
yield break;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
_attDone = false;
|
|
203
|
+
_ATT_RequestPermission(OnATTCallback);
|
|
204
|
+
yield return new WaitUntil(() => _attDone);
|
|
205
|
+
}
|
|
206
|
+
#endif
|
|
207
|
+
|
|
208
|
+
void Awake()
|
|
209
|
+
{
|
|
210
|
+
DontDestroyOnLoad(gameObject);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
IEnumerator Start()
|
|
214
|
+
{
|
|
215
|
+
#if UNITY_IOS && !UNITY_EDITOR
|
|
216
|
+
// Request ATT before initializing LevelPlay to maximise ad fill rate
|
|
217
|
+
yield return RequestATT();
|
|
218
|
+
#else
|
|
219
|
+
yield return null; // Editor / Android: skip ATT
|
|
220
|
+
#endif
|
|
221
|
+
InitializeLevelPlay();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private void InitializeLevelPlay()
|
|
225
|
+
{
|
|
226
|
+
// Add privacy settings here before Init (see Step 6.5)
|
|
227
|
+
LevelPlay.OnInitSuccess += OnInitSuccess;
|
|
228
|
+
LevelPlay.OnInitFailed += OnInitFailed;
|
|
229
|
+
LevelPlay.Init(appKey);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
private void OnInitSuccess(LevelPlayConfiguration config)
|
|
233
|
+
{
|
|
234
|
+
Debug.Log("LevelPlay SDK initialized successfully");
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private void OnInitFailed(LevelPlayInitError error)
|
|
238
|
+
{
|
|
239
|
+
Debug.LogError($"LevelPlay initialization failed: {error.ErrorMessage}");
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
void OnDestroy()
|
|
243
|
+
{
|
|
244
|
+
LevelPlay.OnInitSuccess -= OnInitSuccess;
|
|
245
|
+
LevelPlay.OnInitFailed -= OnInitFailed;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**Key points:**
|
|
251
|
+
- `[AOT.MonoPInvokeCallback]` is required for IL2CPP builds — without it the native callback will crash on device
|
|
252
|
+
- `[DllImport("__Internal")]` binds to the native plugin functions
|
|
253
|
+
- `_ATT_GetStatus()` prevents re-prompting users who have already responded
|
|
254
|
+
- `IEnumerator Start()` with `WaitUntil(() => _attDone)` pauses until the user responds to the ATT dialog
|
|
255
|
+
- `#if UNITY_IOS && !UNITY_EDITOR` guards ensure ATT code only compiles for iOS device builds
|
|
256
|
+
|
|
257
|
+
## Privacy Manifest
|
|
258
|
+
|
|
259
|
+
### iOS 17+ Requirements
|
|
260
|
+
|
|
261
|
+
Apple requires apps to declare data types collected and the reasons for using certain APIs. LevelPlay SDK includes a privacy manifest, but you should be aware of what it declares.
|
|
262
|
+
|
|
263
|
+
### What LevelPlay Declares
|
|
264
|
+
|
|
265
|
+
The LevelPlay SDK's privacy manifest typically declares:
|
|
266
|
+
- **Data Collection**: Device identifiers (IDFA), usage data, location (if used)
|
|
267
|
+
- **Required Reason APIs**: User defaults, file timestamp, system boot time, disk space
|
|
268
|
+
- **Tracking**: Yes (for personalized advertising)
|
|
269
|
+
|
|
270
|
+
### Your App's Privacy Manifest
|
|
271
|
+
|
|
272
|
+
Ensure your app's privacy manifest (if you have one) aligns with LevelPlay's declarations:
|
|
273
|
+
|
|
274
|
+
1. Check for `PrivacyInfo.xcprivacy` in your Xcode project
|
|
275
|
+
2. Verify it includes LevelPlay's data types
|
|
276
|
+
3. Update your App Store privacy declarations accordingly
|
|
277
|
+
|
|
278
|
+
## Xcode Build Settings
|
|
279
|
+
|
|
280
|
+
### Required iOS Capabilities
|
|
281
|
+
|
|
282
|
+
LevelPlay SDK requires certain capabilities to function properly:
|
|
283
|
+
|
|
284
|
+
1. Open your Xcode project after building from Unity
|
|
285
|
+
2. Select your target > **Signing & Capabilities**
|
|
286
|
+
3. Verify these frameworks are included (LevelPlay should add them automatically):
|
|
287
|
+
- **AdSupport.framework**: For IDFA access
|
|
288
|
+
- **AppTrackingTransparency.framework**: For ATT (iOS 14+)
|
|
289
|
+
- **StoreKit.framework**: For SKAdNetwork
|
|
290
|
+
|
|
291
|
+
### App Transport Security (ATS) Configuration
|
|
292
|
+
|
|
293
|
+
To ensure ads load correctly, configure App Transport Security in your Info.plist:
|
|
294
|
+
|
|
295
|
+
**Option 1: Allow arbitrary loads (easiest, less secure)**
|
|
296
|
+
|
|
297
|
+
Add this to your Info.plist:
|
|
298
|
+
```xml
|
|
299
|
+
<key>NSAppTransportSecurity</key>
|
|
300
|
+
<dict>
|
|
301
|
+
<key>NSAllowsArbitraryLoads</key>
|
|
302
|
+
<true/>
|
|
303
|
+
</dict>
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Option 2: Allow specific domains (more secure)**
|
|
307
|
+
|
|
308
|
+
If you prefer to only allow specific ad network domains:
|
|
309
|
+
```xml
|
|
310
|
+
<key>NSAppTransportSecurity</key>
|
|
311
|
+
<dict>
|
|
312
|
+
<key>NSExceptionDomains</key>
|
|
313
|
+
<dict>
|
|
314
|
+
<key>ironsrc.com</key>
|
|
315
|
+
<dict>
|
|
316
|
+
<key>NSIncludesSubdomains</key>
|
|
317
|
+
<true/>
|
|
318
|
+
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
|
319
|
+
<true/>
|
|
320
|
+
</dict>
|
|
321
|
+
<!-- Add other ad network domains as needed -->
|
|
322
|
+
</dict>
|
|
323
|
+
</dict>
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
**Note:** Most ad networks require HTTP access for legacy ad creatives. Without proper ATS configuration, some ads may fail to load.
|
|
327
|
+
|
|
328
|
+
**When to configure:** Before building for iOS. This can be done in Unity's PostProcessBuild or manually in Xcode after export.
|
|
329
|
+
|
|
330
|
+
### Recommended Xcode Build Settings
|
|
331
|
+
|
|
332
|
+
In Xcode, verify these settings:
|
|
333
|
+
|
|
334
|
+
- **Deployment Target**: see the [LevelPlay iOS SDK integration guide](https://docs.unity.com/en-us/grow/levelplay/sdk/ios/sdk-integration) for the currently supported minimum
|
|
335
|
+
- **Enable Bitcode**: No
|
|
336
|
+
- **Other Linker Flags**: Should include `-ObjC` (automatically added by Unity)
|
|
337
|
+
|
|
338
|
+
## Testing on iOS
|
|
339
|
+
|
|
340
|
+
### Test Device Setup
|
|
341
|
+
|
|
342
|
+
1. Build and run on a physical iOS device (simulators have limitations)
|
|
343
|
+
2. For ATT testing:
|
|
344
|
+
- Go to **Settings > Privacy & Security > Tracking**
|
|
345
|
+
- You can reset ATT prompt status by going to **Settings > General > Transfer or Reset iPhone > Reset > Reset Location & Privacy**
|
|
346
|
+
|
|
347
|
+
### Integration Validation
|
|
348
|
+
|
|
349
|
+
After building to iOS:
|
|
350
|
+
|
|
351
|
+
```csharp
|
|
352
|
+
void Start()
|
|
353
|
+
{
|
|
354
|
+
#if UNITY_IOS
|
|
355
|
+
LevelPlay.OnInitSuccess += OnInitSuccess;
|
|
356
|
+
LevelPlay.OnInitFailed += OnInitFailed;
|
|
357
|
+
LevelPlay.Init("YOUR_APP_KEY");
|
|
358
|
+
#endif
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
void OnInitSuccess(LevelPlayConfiguration config)
|
|
362
|
+
{
|
|
363
|
+
Debug.Log("LevelPlay initialized successfully on iOS");
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
void OnInitFailed(LevelPlayInitError error)
|
|
367
|
+
{
|
|
368
|
+
Debug.LogError($"LevelPlay init failed on iOS: {error.ErrorMessage}");
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Check the Xcode console for initialization output. Look for:
|
|
373
|
+
- ✅ "LevelPlay initialized successfully on iOS"
|
|
374
|
+
- ❌ Any initialization errors or warnings
|
|
375
|
+
|
|
376
|
+
### Testing Ads on iOS
|
|
377
|
+
|
|
378
|
+
1. **Test mode**: Enable test mode in your LevelPlay dashboard
|
|
379
|
+
2. **Real ads**: Disable test mode and test with real ads (use low-value test account)
|
|
380
|
+
3. **Different ATT states**: Test with:
|
|
381
|
+
- ATT granted (tracking allowed)
|
|
382
|
+
- ATT denied (tracking disallowed)
|
|
383
|
+
- ATT restricted (device-level restriction)
|
|
384
|
+
|
|
385
|
+
## Common iOS Issues
|
|
386
|
+
|
|
387
|
+
### Issue: ATT prompt not showing
|
|
388
|
+
|
|
389
|
+
**Causes:**
|
|
390
|
+
- Missing `NSUserTrackingUsageDescription` in Info.plist
|
|
391
|
+
- ATT already determined on device
|
|
392
|
+
- Testing on iOS Simulator (use real device)
|
|
393
|
+
|
|
394
|
+
**Solutions:**
|
|
395
|
+
- Verify `iOSPostBuild.cs` exists in `Assets/Editor/` and ran successfully (check console for "iOSPostBuild: NSUserTrackingUsageDescription added to Info.plist")
|
|
396
|
+
- Reset privacy settings on device: **Settings > General > Transfer or Reset iPhone > Reset > Reset Location & Privacy**
|
|
397
|
+
- Test on physical iOS device
|
|
398
|
+
|
|
399
|
+
### Issue: Ads not loading after ATT denial
|
|
400
|
+
|
|
401
|
+
**This is expected behavior:**
|
|
402
|
+
- When users deny tracking, personalized ads are limited
|
|
403
|
+
- Non-personalized ads may still serve
|
|
404
|
+
- Revenue may be lower for users who deny tracking
|
|
405
|
+
|
|
406
|
+
**What to do:**
|
|
407
|
+
- Continue with LevelPlay initialization regardless of ATT response
|
|
408
|
+
- Don't block features if tracking is denied
|
|
409
|
+
- Comply with Apple's guidelines
|
|
410
|
+
|
|
411
|
+
### Issue: SKAdNetwork IDs missing
|
|
412
|
+
|
|
413
|
+
**Causes:**
|
|
414
|
+
- Outdated LevelPlay package
|
|
415
|
+
- Custom build postprocessor conflict
|
|
416
|
+
- Manual Info.plist modifications
|
|
417
|
+
|
|
418
|
+
**Solutions:**
|
|
419
|
+
- Update to latest LevelPlay Unity Package
|
|
420
|
+
- Check for conflicting build scripts
|
|
421
|
+
- Let LevelPlay handle SKAdNetwork IDs automatically
|
|
422
|
+
|
|
423
|
+
### Issue: App rejected for privacy reasons
|
|
424
|
+
|
|
425
|
+
**Common causes:**
|
|
426
|
+
- Missing privacy manifest declarations
|
|
427
|
+
- Incorrect ATT usage description
|
|
428
|
+
- Data collection not properly declared
|
|
429
|
+
|
|
430
|
+
**Solutions:**
|
|
431
|
+
- Review Apple's App Privacy Details guidelines
|
|
432
|
+
- Ensure ATT description is clear and user-friendly
|
|
433
|
+
- Declare all data types collected in App Store Connect
|
|
434
|
+
- Keep LevelPlay SDK updated (includes privacy manifest updates)
|
|
435
|
+
|
|
436
|
+
## iOS Privacy Checklist
|
|
437
|
+
|
|
438
|
+
Before submitting to App Store:
|
|
439
|
+
|
|
440
|
+
- [ ] ATT prompt implemented: `ATTRequester.mm` in `Assets/Plugins/iOS/`, `iOSPostBuild.cs` in `Assets/Editor/`, `LevelPlayInitializer.cs` updated to `IEnumerator Start()`
|
|
441
|
+
- [ ] SKAdNetwork IDs included in Info.plist
|
|
442
|
+
- [ ] Privacy manifest present and accurate
|
|
443
|
+
- [ ] App Store privacy declarations filled out
|
|
444
|
+
- [ ] Data collection disclosed transparently
|
|
445
|
+
- [ ] Tested on real iOS devices
|
|
446
|
+
- [ ] Verified ads load and show correctly
|
|
447
|
+
- [ ] Tested both ATT granted and denied scenarios
|
|
448
|
+
- [ ] No tracking of users who denied ATT
|
|
449
|
+
- [ ] Compliant with Apple's advertising policies
|
|
450
|
+
|
|
451
|
+
## Additional Resources
|
|
452
|
+
|
|
453
|
+
### Apple Documentation
|
|
454
|
+
- [App Tracking Transparency Guide](https://developer.apple.com/documentation/apptrackingtransparency)
|
|
455
|
+
- [SKAdNetwork Documentation](https://developer.apple.com/documentation/storekit/skadnetwork)
|
|
456
|
+
- [User Privacy and Data Use](https://developer.apple.com/app-store/user-privacy-and-data-use/)
|
|
457
|
+
|
|
458
|
+
### LevelPlay Documentation
|
|
459
|
+
- Refer to LevelPlay's Unity documentation for the latest iOS setup requirements
|
|
460
|
+
- Check for SDK update notes regarding iOS changes
|
|
461
|
+
- Review LevelPlay's privacy manifest documentation
|
|
462
|
+
|
|
463
|
+
## Version-Specific Notes
|
|
464
|
+
|
|
465
|
+
### iOS 14.5+
|
|
466
|
+
- ATT required for IDFA access
|
|
467
|
+
- Personalized ads limited without tracking permission
|
|
468
|
+
|
|
469
|
+
### iOS 15+
|
|
470
|
+
- Custom product pages support
|
|
471
|
+
- App privacy report visible to users
|
|
472
|
+
|
|
473
|
+
### iOS 16+
|
|
474
|
+
- Additional privacy enhancements
|
|
475
|
+
- More granular location privacy
|
|
476
|
+
|
|
477
|
+
### iOS 17+
|
|
478
|
+
- Privacy manifest required
|
|
479
|
+
- Increased API usage disclosure requirements
|
|
480
|
+
- SDK transparency requirements
|
|
481
|
+
|
|
482
|
+
## Best Practices
|
|
483
|
+
|
|
484
|
+
1. **Request ATT at an appropriate time**: Not immediately on first launch, but before showing ads
|
|
485
|
+
2. **Explain value to users**: Help users understand why you're requesting tracking
|
|
486
|
+
3. **Respect user choice**: Never block app functionality if tracking is denied
|
|
487
|
+
4. **Keep SDK updated**: Apple requirements change frequently
|
|
488
|
+
5. **Test thoroughly**: Test on real devices with different iOS versions
|
|
489
|
+
6. **Monitor metrics**: Track opt-in rates and ad performance post-iOS 14.5
|
|
490
|
+
7. **Stay compliant**: Follow Apple's Human Interface Guidelines for ATT
|
|
491
|
+
8. **Prepare for rejections**: Have documentation ready if Apple requests clarification
|