Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>

This commit is contained in:
Matt Bruce 2026-02-03 17:25:43 -06:00
parent c153b16593
commit ac35666208
7 changed files with 87 additions and 73 deletions

58
Info.plist Normal file
View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>CFBundleDisplayName</key>
<string>$(PRODUCT_NAME)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>SelfieCam needs camera access to display your live selfie preview, apply real-time filters and ring light effects, capture high-quality photos, and enable advanced features like Center Stage auto-framing.</string>
<key>NSMicrophoneUsageDescription</key>
<string>SelfieCam needs microphone access for the camera framework to initialize properly. Audio is not recorded.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>SelfieCam needs photo library access to automatically save your captured photos to your device, making them available in the Photos app and other compatible applications.</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
<key>UISceneConfigurations</key>
<dict/>
</dict>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>RevenueCatAPIKey</key>
<string>$(REVENUECAT_API_KEY)</string>
</dict>
</plist>

View File

@ -435,20 +435,8 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_AppClipDomain = "$(APPCLIP_DOMAIN)";
INFOPLIST_KEY_AppGroupIdentifier = "$(APP_GROUP_IDENTIFIER)";
INFOPLIST_KEY_CFBundleDisplayName = "$(PRODUCT_NAME)";
INFOPLIST_KEY_CloudKitContainerIdentifier = "$(CLOUDKIT_CONTAINER_IDENTIFIER)";
INFOPLIST_KEY_NSCameraUsageDescription = "SelfieCam needs camera access to display your live selfie preview, apply real-time filters and ring light effects, capture high-quality photos, and enable advanced features like Center Stage auto-framing.";
INFOPLIST_KEY_NSMicrophoneUsageDescription = "SelfieCam needs microphone access for the camera framework to initialize properly. Audio is not recorded.";
INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "SelfieCam needs photo library access to automatically save your captured photos to your device, making them available in the Photos app and other compatible applications.";
INFOPLIST_KEY_PublicAppName = "$(PRODUCT_NAME)";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
GENERATE_INFOPLIST_FILE = NO;
INFOPLIST_FILE = Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 18.6;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@ -477,20 +465,8 @@
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_AppClipDomain = "$(APPCLIP_DOMAIN)";
INFOPLIST_KEY_AppGroupIdentifier = "$(APP_GROUP_IDENTIFIER)";
INFOPLIST_KEY_CFBundleDisplayName = "$(PRODUCT_NAME)";
INFOPLIST_KEY_CloudKitContainerIdentifier = "$(CLOUDKIT_CONTAINER_IDENTIFIER)";
INFOPLIST_KEY_NSCameraUsageDescription = "SelfieCam needs camera access to display your live selfie preview, apply real-time filters and ring light effects, capture high-quality photos, and enable advanced features like Center Stage auto-framing.";
INFOPLIST_KEY_NSMicrophoneUsageDescription = "SelfieCam needs microphone access for the camera framework to initialize properly. Audio is not recorded.";
INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "SelfieCam needs photo library access to automatically save your captured photos to your device, making them available in the Photos app and other compatible applications.";
INFOPLIST_KEY_PublicAppName = "$(PRODUCT_NAME)";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
GENERATE_INFOPLIST_FILE = NO;
INFOPLIST_FILE = Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 18.6;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",

View File

@ -2,3 +2,4 @@
// Configuration for Debug builds
#include "Base.xcconfig"
#include "Secrets.debug.xcconfig"

View File

@ -2,3 +2,4 @@
// Configuration for Release builds
#include "Base.xcconfig"
#include "Secrets.release.xcconfig"

View File

@ -1,20 +0,0 @@
// Secrets.swift
// ⚠️ DO NOT COMMIT THE ACTUAL Secrets.swift FILE TO VERSION CONTROL
//
// Copy this file to Secrets.swift and fill in your actual values.
// Secrets.swift is gitignored.
import Foundation
enum Secrets {
/// RevenueCat API Key
/// - Debug: Use your test/sandbox API key (starts with "test_")
/// - Release: Use your production API key (starts with "appl_")
static let revenueCatAPIKey: String = {
#if DEBUG
return "test_YOUR_TEST_KEY_HERE"
#else
return "appl_YOUR_PRODUCTION_KEY_HERE"
#endif
}()
}

View File

@ -1,22 +0,0 @@
// Secrets.xcconfig.template
//
// INSTRUCTIONS:
// This project uses separate secrets files for Debug and Release builds:
//
// 1. Copy this file to "Secrets.debug.xcconfig" for development/testing
// - Use your RevenueCat TEST API key (starts with test_)
// - Sandbox purchases, no real money charged
//
// 2. Copy this file to "Secrets.release.xcconfig" for App Store builds
// - Use your RevenueCat PRODUCTION API key (starts with appl_)
// - Real purchases, charges real money
//
// 3. NEVER commit the actual secrets files to version control
//
// The actual Secrets.*.xcconfig files are gitignored for security.
// RevenueCat API Key
// Get this from: RevenueCat Dashboard > Project Settings > API Keys
// - Test key: Use "Public App-Specific API Key" from test environment
// - Production key: Use "Public App-Specific API Key" from production environment
REVENUECAT_API_KEY = your_revenuecat_api_key_here

View File

@ -16,10 +16,30 @@ final class PremiumManager: PremiumManaging {
/// Reads the RevenueCat API key from the Secrets configuration file
private static var apiKey: String {
let key = Secrets.revenueCatAPIKey
guard !key.isEmpty, key != "YOUR_REVENUECAT_API_KEY_HERE" else {
let key = (Bundle.main.object(forInfoDictionaryKey: "RevenueCatAPIKey") as? String) ?? ""
let placeholders = [
"",
"YOUR_REVENUECAT_API_KEY_HERE",
"test_YOUR_TEST_KEY_HERE",
"appl_YOUR_PRODUCTION_KEY_HERE"
]
#if DEBUG
let prefix = key.split(separator: "_").first.map(String.init) ?? "missing"
let keyStatus = key.isEmpty ? "empty" : "present"
print(" [PremiumManager] RevenueCatAPIKey \(keyStatus), prefix=\(prefix)")
if let infoPath = Bundle.main.path(forResource: "Info", ofType: "plist"),
let infoDict = NSDictionary(contentsOfFile: infoPath) as? [String: Any] {
let rawValue = infoDict["RevenueCatAPIKey"] as? String ?? ""
let rawPrefix = rawValue.split(separator: "_").first.map(String.init) ?? "missing"
let rawStatus = rawValue.isEmpty ? "empty" : "present"
print(" [PremiumManager] Info.plist RevenueCatAPIKey \(rawStatus), prefix=\(rawPrefix)")
} else {
print(" [PremiumManager] Info.plist not found in bundle")
}
#endif
guard !placeholders.contains(key) else {
#if DEBUG
print("⚠️ [PremiumManager] RevenueCat API key not configured. See Configuration/Secrets.swift.template")
print("⚠️ [PremiumManager] RevenueCat API key not configured. Check Secrets.debug.xcconfig / Secrets.release.xcconfig")
#endif
return ""
}