Commit 8628b13b authored by yqz's avatar yqz

Merge branch 'dev_main' into yQz0507

* dev_main:
  fix bugs
  adjust 数据上报
parents c91e1482 6542bcb4
...@@ -15,6 +15,10 @@ ...@@ -15,6 +15,10 @@
049F146D2DDB1F64007B5A9B /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04BD915F2D9D68AD00055CEB /* SwiftUI.framework */; }; 049F146D2DDB1F64007B5A9B /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04BD915F2D9D68AD00055CEB /* SwiftUI.framework */; };
049F14782DDB1F66007B5A9B /* LockSreenExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 049F146B2DDB1F64007B5A9B /* LockSreenExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 049F14782DDB1F66007B5A9B /* LockSreenExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 049F146B2DDB1F64007B5A9B /* LockSreenExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
04BBB4E62DC0748F00D7E3AB /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04BBB4E52DC0748F00D7E3AB /* StoreKit.framework */; }; 04BBB4E62DC0748F00D7E3AB /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04BBB4E52DC0748F00D7E3AB /* StoreKit.framework */; };
04C299E22DDE02530054D76C /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04C299E12DDE02530054D76C /* AdSupport.framework */; };
04C299E42DDE025D0054D76C /* AdServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04C299E32DDE025D0054D76C /* AdServices.framework */; };
04C299E62DDE026D0054D76C /* AppTrackingTransparency.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04C299E52DDE026D0054D76C /* AppTrackingTransparency.framework */; };
04CA06622DDDB40E009A15E3 /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 04CA06612DDDB40E009A15E3 /* KeychainSwift */; };
04CF31702DA7E78F001C87CA /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04BD7A442DA3BA1700A24C4B /* Intents.framework */; }; 04CF31702DA7E78F001C87CA /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04BD7A442DA3BA1700A24C4B /* Intents.framework */; };
04CF31772DA7E790001C87CA /* ChargeShow.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 04CF316F2DA7E78F001C87CA /* ChargeShow.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 04CF31772DA7E790001C87CA /* ChargeShow.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 04CF316F2DA7E78F001C87CA /* ChargeShow.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
04CF317D2DA7E7BE001C87CA /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 04CF317C2DA7E7BE001C87CA /* Intents.intentdefinition */; }; 04CF317D2DA7E7BE001C87CA /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 04CF317C2DA7E7BE001C87CA /* Intents.intentdefinition */; };
...@@ -83,6 +87,9 @@ ...@@ -83,6 +87,9 @@
04BD7A4F2DA3BA1700A24C4B /* IntentsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IntentsUI.framework; path = System/Library/Frameworks/IntentsUI.framework; sourceTree = SDKROOT; }; 04BD7A4F2DA3BA1700A24C4B /* IntentsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IntentsUI.framework; path = System/Library/Frameworks/IntentsUI.framework; sourceTree = SDKROOT; };
04BD915D2D9D68AD00055CEB /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; 04BD915D2D9D68AD00055CEB /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
04BD915F2D9D68AD00055CEB /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; 04BD915F2D9D68AD00055CEB /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
04C299E12DDE02530054D76C /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; };
04C299E32DDE025D0054D76C /* AdServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdServices.framework; path = System/Library/Frameworks/AdServices.framework; sourceTree = SDKROOT; };
04C299E52DDE026D0054D76C /* AppTrackingTransparency.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppTrackingTransparency.framework; path = System/Library/Frameworks/AppTrackingTransparency.framework; sourceTree = SDKROOT; };
04CF316F2DA7E78F001C87CA /* ChargeShow.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ChargeShow.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 04CF316F2DA7E78F001C87CA /* ChargeShow.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ChargeShow.appex; sourceTree = BUILT_PRODUCTS_DIR; };
04CF317C2DA7E7BE001C87CA /* Intents.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = Intents.intentdefinition; sourceTree = "<group>"; }; 04CF317C2DA7E7BE001C87CA /* Intents.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = Intents.intentdefinition; sourceTree = "<group>"; };
04EC294C2DD342220049739A /* SVProgressHUD.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SVProgressHUD.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 04EC294C2DD342220049739A /* SVProgressHUD.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SVProgressHUD.framework; sourceTree = BUILT_PRODUCTS_DIR; };
...@@ -197,9 +204,13 @@ ...@@ -197,9 +204,13 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
04C299E62DDE026D0054D76C /* AppTrackingTransparency.framework in Frameworks */,
04BBB4E62DC0748F00D7E3AB /* StoreKit.framework in Frameworks */,
04C299E42DDE025D0054D76C /* AdServices.framework in Frameworks */,
04C299E22DDE02530054D76C /* AdSupport.framework in Frameworks */,
042EF7462DD4A3F90028DE2C /* Kingfisher in Frameworks */, 042EF7462DD4A3F90028DE2C /* Kingfisher in Frameworks */,
3A00E856852A8783E544CD7D /* Pods_PhoneManager.framework in Frameworks */, 3A00E856852A8783E544CD7D /* Pods_PhoneManager.framework in Frameworks */,
04BBB4E62DC0748F00D7E3AB /* StoreKit.framework in Frameworks */, 04CA06622DDDB40E009A15E3 /* KeychainSwift in Frameworks */,
04EC294B2DD33B480049739A /* GoogleSignIn in Frameworks */, 04EC294B2DD33B480049739A /* GoogleSignIn in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
...@@ -210,6 +221,9 @@ ...@@ -210,6 +221,9 @@
27ECDADD9059AB5043B8E1E9 /* Frameworks */ = { 27ECDADD9059AB5043B8E1E9 /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
04C299E52DDE026D0054D76C /* AppTrackingTransparency.framework */,
04C299E32DDE025D0054D76C /* AdServices.framework */,
04C299E12DDE02530054D76C /* AdSupport.framework */,
04EC294C2DD342220049739A /* SVProgressHUD.framework */, 04EC294C2DD342220049739A /* SVProgressHUD.framework */,
04BBB4E52DC0748F00D7E3AB /* StoreKit.framework */, 04BBB4E52DC0748F00D7E3AB /* StoreKit.framework */,
6028F60B696E2F97EAA2325C /* Pods_PhoneManager.framework */, 6028F60B696E2F97EAA2325C /* Pods_PhoneManager.framework */,
...@@ -387,6 +401,7 @@ ...@@ -387,6 +401,7 @@
packageReferences = ( packageReferences = (
04EC26182DD33B070049739A /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */, 04EC26182DD33B070049739A /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */,
042EF7442DD4A3780028DE2C /* XCRemoteSwiftPackageReference "Kingfisher" */, 042EF7442DD4A3780028DE2C /* XCRemoteSwiftPackageReference "Kingfisher" */,
04CA06602DDDB3F8009A15E3 /* XCRemoteSwiftPackageReference "keychain-swift" */,
); );
preferredProjectObjectVersion = 77; preferredProjectObjectVersion = 77;
productRefGroup = EB388E5C2D8A61A800629B0D /* Products */; productRefGroup = EB388E5C2D8A61A800629B0D /* Products */;
...@@ -1012,6 +1027,14 @@ ...@@ -1012,6 +1027,14 @@
minimumVersion = 8.3.2; minimumVersion = 8.3.2;
}; };
}; };
04CA06602DDDB3F8009A15E3 /* XCRemoteSwiftPackageReference "keychain-swift" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/evgenyneu/keychain-swift.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 24.0.0;
};
};
04EC26182DD33B070049739A /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */ = { 04EC26182DD33B070049739A /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */ = {
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/google/GoogleSignIn-iOS"; repositoryURL = "https://github.com/google/GoogleSignIn-iOS";
...@@ -1028,6 +1051,11 @@ ...@@ -1028,6 +1051,11 @@
package = 042EF7442DD4A3780028DE2C /* XCRemoteSwiftPackageReference "Kingfisher" */; package = 042EF7442DD4A3780028DE2C /* XCRemoteSwiftPackageReference "Kingfisher" */;
productName = Kingfisher; productName = Kingfisher;
}; };
04CA06612DDDB40E009A15E3 /* KeychainSwift */ = {
isa = XCSwiftPackageProductDependency;
package = 04CA06602DDDB3F8009A15E3 /* XCRemoteSwiftPackageReference "keychain-swift" */;
productName = KeychainSwift;
};
04EC294A2DD33B480049739A /* GoogleSignIn */ = { 04EC294A2DD33B480049739A /* GoogleSignIn */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = 04EC26182DD33B070049739A /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */; package = 04EC26182DD33B070049739A /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */;
......
{ {
"originHash" : "c64907f28a6f12cd9166d202e75e2e3776dc750a2e196ae17a655106dc8ba134", "originHash" : "de1a4dc6f64c5ce471b3f7c477ef76458170ad953fc5100955926b1f2889707a",
"pins" : [ "pins" : [
{ {
"identity" : "app-check", "identity" : "app-check",
...@@ -55,6 +55,15 @@ ...@@ -55,6 +55,15 @@
"version" : "4.1.1" "version" : "4.1.1"
} }
}, },
{
"identity" : "keychain-swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/evgenyneu/keychain-swift.git",
"state" : {
"revision" : "5e1b02b6a9dac2a759a1d5dbc175c86bd192a608",
"version" : "24.0.0"
}
},
{ {
"identity" : "kingfisher", "identity" : "kingfisher",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
......
...@@ -11,6 +11,7 @@ import Photos ...@@ -11,6 +11,7 @@ import Photos
import GoogleMobileAds import GoogleMobileAds
import UserMessagingPlatform import UserMessagingPlatform
import GoogleSignIn import GoogleSignIn
import AdjustSdk
@main @main
class AppDelegate: UIResponder, UIApplicationDelegate { class AppDelegate: UIResponder, UIApplicationDelegate {
...@@ -32,18 +33,36 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ...@@ -32,18 +33,36 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
window?.rootViewController = rootNav window?.rootViewController = rootNav
window?.makeKeyAndVisible() window?.makeKeyAndVisible()
// let Ssoryboard = UIStoryboard(name: "LauchVC", bundle: nil)
//
// if let current = Ssoryboard.instantiateViewController(identifier: "LauchVCID") as? LauchVC {
//
// window?.rootViewController = current
// window?.makeKeyAndVisible()
// }
// 小组件数据 同步 // 小组件数据 同步
let battery = WidgetPublicModel.battery() let battery = WidgetPublicModel.battery()
let storage = WidgetPublicModel.UseDiskSpace() * 100 let storage = WidgetPublicModel.UseDiskSpace() * 100
widgetAppgourp.share.PushWidgetData(battery: Int(battery), storage: Int(storage)) widgetAppgourp.share.PushWidgetData(battery: Int(battery), storage: Int(storage))
let battery = WidgetPublicModel.battery()
let storage = WidgetPublicModel.UseDiskSpace() * 100
widgetAppgourp.share.PushWidgetData(battery: Int(battery), storage: Int(storage))
//初始化adjust
let yourAppToken = "6mouvwgw7ksg"
#if DEBUG
let environment = ADJEnvironmentSandbox
let adjustConfig = ADJConfig(
appToken: yourAppToken,
environment: environment)
adjustConfig?.logLevel = ADJLogLevel.verbose
#else
let environment = ADJEnvironmentProduction
let adjustConfig = ADJConfig(
appToken: yourAppToken,
environment: environment)
adjustConfig?.logLevel = ADJLogLevel.suppress
#endif
adjustConfig?.delegate = self
Adjust.initSdk(adjustConfig)
// 获取内购价格 // 获取内购价格
IAPManager.share.fetchProducts { p in IAPManager.share.fetchProducts { p in
Print("获取内购商品信息",p as Any) Print("获取内购商品信息",p as Any)
...@@ -60,6 +79,22 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ...@@ -60,6 +79,22 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// 设置app动态按钮 // 设置app动态按钮
setupDynamicShortcuts() setupDynamicShortcuts()
Adjust.attribution { attribution in
Print("获取归因数据11",attribution?.jsonResponse)
// let trackerToken = attribution?.trackerToken
// let trackerName = attribution?.trackerName
// let network = attribution?.network
// let campaign = attribution?.campaign
// let adgroup = attribution?.adgroup
// let creative = attribution?.creative
// let clickLabel = attribution?.clickLabel
// let costType = attribution?.costType
// let costAmount = attribution?.costAmount
// let costCurrency = attribution?.costCurrency
}
return true return true
} }
...@@ -141,6 +176,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ...@@ -141,6 +176,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
case .NoNet: case .NoNet:
break break
case .WIFI,.WWAN: case .WIFI,.WWAN:
if UserDef.shard.isFirstStart{
Print("首次启动获取网络上报")
APIReportManager.shared.startReport(type: .app_start)
UserDef.shard.saveFirstStart()
}
break break
} }
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
import Foundation import Foundation
import UIKit import UIKit
import AdjustSdk
extension AppDelegate{ extension AppDelegate{
...@@ -15,7 +16,7 @@ extension AppDelegate{ ...@@ -15,7 +16,7 @@ extension AppDelegate{
type: "com.app.phonemanager.iap.distance", type: "com.app.phonemanager.iap.distance",
localizedTitle: "Unlock Exclusive Discounts", localizedTitle: "Unlock Exclusive Discounts",
localizedSubtitle: "Your special offer is awaiting—don't miss this limited-time second chance benefit!", localizedSubtitle: "Your special offer is awaiting—don't miss this limited-time second chance benefit!",
icon: UIApplicationShortcutIcon(systemImageName: "star.fill"), icon: UIApplicationShortcutIcon(templateImageName: ""), //UIApplicationShortcutIcon(systemImageName: "star.fill"),
userInfo: nil userInfo: nil
) )
UIApplication.shared.shortcutItems = [shortcutItem] UIApplication.shared.shortcutItems = [shortcutItem]
...@@ -52,3 +53,17 @@ extension AppDelegate{ ...@@ -52,3 +53,17 @@ extension AppDelegate{
} }
} }
extension AppDelegate:AdjustDelegate{
func adjustAttributionChanged(_ attribution: ADJAttribution?) {
guard let attribution = attribution else { return }
// 可以将这些数据上报给自己的服务器或者做其他处理
print("归因数据:", attribution)
}
}
...@@ -136,6 +136,11 @@ class GroupDatabase { ...@@ -136,6 +136,11 @@ class GroupDatabase {
// 查询所有数据 // 查询所有数据
func queryAll() -> [(localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int, groupId: String)] { func queryAll() -> [(localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int, groupId: String)] {
if PhotoManager.shared.permissionStatus != .authorized {
return []
}
let queryStatementString = "SELECT * FROM groups ORDER BY rowid DESC;" let queryStatementString = "SELECT * FROM groups ORDER BY rowid DESC;"
var queryStatement: OpaquePointer? var queryStatement: OpaquePointer?
var result: [(localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int, groupId: String)] = [] var result: [(localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int, groupId: String)] = []
......
...@@ -133,6 +133,12 @@ class TrashDatabase { ...@@ -133,6 +133,12 @@ class TrashDatabase {
// 查询所有数据 // 查询所有数据
func queryAll() -> [(localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int)] { func queryAll() -> [(localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int)] {
if PhotoManager.shared.permissionStatus != .authorized {
return []
}
let queryStatementString = "SELECT * FROM trash;" let queryStatementString = "SELECT * FROM trash;"
var queryStatement: OpaquePointer? var queryStatement: OpaquePointer?
var result: [(localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int)] = [] var result: [(localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int)] = []
......
//
// AESCrypto.swift
// PhoneManager
//
// Created by edy on 2025/5/21.
//
import Foundation
import CommonCrypto
import CryptoKit
struct AESCrypto {
// 需要修改为与安卓一致的密钥
private static let key = "z1lle6aeg531um0k"
static func encryptGCM(_ string: String) -> String? {
guard let data = string.data(using: .utf8),
let keyData = key.data(using: .utf8) else { return nil }
do {
// CryptoKit 自动生成 nonce,长度可能与安卓不一致
let nonce = AES.GCM.Nonce()
let symmetricKey = SymmetricKey(data: keyData)
let sealedBox = try AES.GCM.seal(data, using: symmetricKey, nonce: nonce)
let combined = sealedBox.combined
return combined?.base64EncodedString()
} catch {
print("加密错误: \(error)")
return nil
}
}
/// AES-GCM 解密方法
/// - Parameter encrypted: 加密后的 base64 字符串(包含 nonce 和认证标签)
/// - Returns: 返回解密后的原始字符串
static func decryptGCM(_ encrypted: String) -> String? {
guard let combinedData = Data(base64Encoded: encrypted),
let keyData = key.data(using: .utf8) else { return nil }
do {
// 创建 SymmetricKey
let symmetricKey = SymmetricKey(data: keyData)
// 从组合数据创建 sealed box
let sealedBox = try AES.GCM.SealedBox(combined: combinedData)
// 解密数据
let decryptedData = try AES.GCM.open(sealedBox, using: symmetricKey)
// 转换为字符串
return String(data: decryptedData, encoding: .utf8)
} catch {
print("解密错误: \(error)")
return nil
}
}
}
//
// APIReportManager.swift
// PhoneManager
//
// Created by edy on 2025/5/21.
//
import Foundation
struct APIReportManager{
static let shared = APIReportManager()
let bundleId = "com.app.phonemanager"
let hostUrl = "https://rp.sayyedandroid.online/phonemanagersp?pkg=com.app.phonemanager"
let DEBUG = true
// 开始上报
func startReport(type:APIReportEnum,ext:[String:Any] = [:]){
let data = getdataBody(action: type.name, ext: ext)
let bp = getbpBody()
let content = [
"data":data,
"bp":bp
]
Print("上报数据",content)
if let json = content.toJSONString(){
guard let aesString = AESCrypto.encryptGCM(json) else{
return
}
reportAPIRequest(for: aesString)
}
}
private func reportAPIRequest(for aesStr:String){
HttpRequest.postBodyWithString(to: hostUrl, bodyValue: aesStr) { result in
switch result {
case .success(let jsonString):
Print("上报成功",jsonString)
case .failure(let failure):
Print("请求异常",failure.localizedDescription)
}
}
}
private func getdataBody(action:String,ext:[String:Any]) ->[String:Any]{
var dic = [
"action":action,
] as? [String:Any]
if ext.count > 0{
dic?["ext"] = ext
}
return dic ?? [:]
}
private func getbpBody() ->[String:String]{
let body = [
"\(bundleId)_3": UIDevice.current.model, //手机型号
"\(bundleId)_4": "Apple", // 手机厂商
"\(bundleId)_5": UIDevice.current.systemVersion, //系统版本号
"\(bundleId)_8": Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "", // APP版本号
"\(bundleId)_9": DeviceIDManager.shared.deviceID, //UUID
"\(bundleId)_13": "iOS", // platform
"\(bundleId)_14": Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "", //版本号
"\(bundleId)_15": "AppStore", //渠道标识
"\(bundleId)_24": DEBUG ? "debug" : "release", //环境 debug:开发环境 release:正式环境
"\(bundleId)_34": TimeZone.current.identifier, //手机本地时区
"\(bundleId)_35": DeviceIDManager.shared.deviceID //UUID
]
return body
}
}
enum APIReportEnum{
// 广告上报枚举
case ad_pull_start
case ad_pull
case ad_prepare_show
case ad_show
case ad_show_error
case ad_limit_error
case ad_click
case ad_price
// app启动
case app_start
// 归因上报枚举
case source_atrribute
case source_atrribute_error
// 订阅枚举
case apple_billing_error
case apple_billing_click
case apple_billing_consume
case apple_billing_success
// 页面展示枚举
case Duplicates_show
case Similar_show
case Videos_show
case SimilarScreenshots_show
case Screenshots_show
case SimilarVideos_show
case Other_show
case SecretSpace_show
case Charging_show
case Compress_show
case EmailCleaner_show
case Contacts_show
}
extension APIReportEnum{
var name: String {
switch self {
// 广告上报枚举
case .ad_pull_start: return "ad_pull_start"
case .ad_pull: return "ad_pull"
case .ad_prepare_show: return "ad_prepare_show"
case .ad_show: return "ad_show"
case .ad_show_error: return "ad_show_error"
case .ad_limit_error: return "ad_limit_error"
case .ad_click: return "ad_click"
case .ad_price: return "ad_price"
case .app_start: return "app_start"
// 归因上报枚举
case .source_atrribute: return "source_atrribute"
case .source_atrribute_error: return "source_atrribute_error"
// 订阅枚举
case .apple_billing_error: return "apple_billing_error"
case .apple_billing_click: return "apple_billing_click"
case .apple_billing_consume: return "apple_billing_consume"
case .apple_billing_success: return "apple_billing_success"
// 页面展示枚举
case .Duplicates_show: return "Duplicates_show"
case .Similar_show: return "Similar_show"
case .Videos_show: return "Videos_show"
case .SimilarScreenshots_show: return "SimilarScreenshots_show"
case .Screenshots_show: return "Screenshots_show"
case .SimilarVideos_show: return "SimilarVideos_show"
case .Other_show: return "Other_show"
case .SecretSpace_show: return "SecretSpace_show"
case .Charging_show: return "Charging_show"
case .Compress_show: return "Compress_show"
case .EmailCleaner_show: return "EmailCleaner_show"
case .Contacts_show: return "Contacts_show"
}
}
}
import Foundation
import KeychainSwift
class DeviceIDManager {
static let shared = DeviceIDManager()
private let keychain = KeychainSwift()
private let deviceIDKey = "com.app.phonemanager.device_unique_id"
private init() {}
var deviceID: String {
// 尝试从 Keychain 获取已存储的 UUID
if let savedID = keychain.get(deviceIDKey) {
return savedID
}
// 如果没有存储过,生成新的 UUID 并保存
let newID = UUID().uuidString
keychain.set(newID, forKey: deviceIDKey)
return newID
}
}
extension Dictionary where Key == String {
func toJSONString() -> String? {
do {
let jsonData = try JSONSerialization.data(withJSONObject: self, options: [])
if let jsonString = String(data: jsonData, encoding: .utf8) {
return jsonString
}
} catch {
print("JSON转换错误: \(error)")
}
return nil
}
}
\ No newline at end of file
...@@ -45,6 +45,22 @@ enum SubscriptionType { ...@@ -45,6 +45,22 @@ enum SubscriptionType {
case lifetime case lifetime
} }
enum PayState {
case weekSubscribe
case yearSubscribe
case nonConsumable
var productId:String{
switch self {
case .weekSubscribe:
return "com.app.phonemanager.week.member"
case .yearSubscribe:
return "com.app.phonemanager.year.member"
case .nonConsumable:
return "com.app.phonemanager.lifetime.member"
}
}
}
// MARK: - IAPManager // MARK: - IAPManager
class IAPManager: NSObject { class IAPManager: NSObject {
...@@ -56,11 +72,8 @@ class IAPManager: NSObject { ...@@ -56,11 +72,8 @@ class IAPManager: NSObject {
private let productRequestTimeout: TimeInterval = 15 private let productRequestTimeout: TimeInterval = 15
private let alert = PMLoadingHUD.share private let alert = PMLoadingHUD.share
enum PayState { var currentVCName:String = ""
case weekSubscribe
case yearSubscribe
case nonConsumable
}
// MARK: - Properties // MARK: - Properties
private struct ProductID { private struct ProductID {
...@@ -153,36 +166,6 @@ extension IAPManager { ...@@ -153,36 +166,6 @@ extension IAPManager {
} }
// 检查订阅信息
/// - Parameter completion: 回调闭包,返回订阅状态和到期时间
// func checkSubscriptionState(completion: @escaping (_ isSubscribed: Bool, _ expiresDate: Date?) -> Void) {
// verifyReceiptWithApple { result in
// switch result {
// case .success(let receipt):
// // 打印完整收据信息,方便调试
// //print("收据信息:\(receipt)")
// let status = self.checkSubscriptionStatus(receiptInfo: receipt)
// DispatchQueue.main.async {
// completion(status.isActive, status.expiresDate)
// // 更新本地订阅状态
// self.isSubscribed = status.isActive
// #if DEBUG
// if let expDate = status.expiresDate {
// let formatter = DateFormatter()
// formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
// Print("订阅状态:\(status.isActive ? "已订阅" : "未订阅"),到期时间:\(formatter.string(from: expDate))")
// }
// #endif
// }
//
// case .failure(_):
// // 处理错误情况
// self.refreshReceipt()
// completion(false, nil)
// }
// }
// }
// 修改回调方法,增加订阅类型参数 // 修改回调方法,增加订阅类型参数
func checkSubscriptionState(completion: @escaping (_ isSubscribed: Bool, _ subscriptionType: SubscriptionType, _ expiresDate: Date?) -> Void) { func checkSubscriptionState(completion: @escaping (_ isSubscribed: Bool, _ subscriptionType: SubscriptionType, _ expiresDate: Date?) -> Void) {
verifyReceiptWithApple { result in verifyReceiptWithApple { result in
...@@ -211,7 +194,8 @@ extension IAPManager { ...@@ -211,7 +194,8 @@ extension IAPManager {
} }
func purchase(_ state: PayState = .weekSubscribe, completion: @escaping (Result<Bool, IAPError>) -> Void) { func purchase(_ state: PayState = .weekSubscribe, completion: @escaping (Result<Bool, IAPError>) -> Void) {
if state == .weekSubscribe,weekProduct == nil{ if state == .weekSubscribe,weekProduct == nil{
completion(.failure(.noProductsFound)) completion(.failure(.noProductsFound))
return return
...@@ -245,6 +229,8 @@ extension IAPManager { ...@@ -245,6 +229,8 @@ extension IAPManager {
payment = SKPayment(product: lifetimeProduct!) payment = SKPayment(product: lifetimeProduct!)
} }
APIReportManager.shared.startReport(type: .apple_billing_click, ext: ["productId":payment.productIdentifier,"from":currentVCName])
SKPaymentQueue.default().add(payment) SKPaymentQueue.default().add(payment)
alert.show("Processing the purchase request...", "") alert.show("Processing the purchase request...", "")
} }
...@@ -516,56 +502,6 @@ extension IAPManager: SKPaymentTransactionObserver { ...@@ -516,56 +502,6 @@ extension IAPManager: SKPaymentTransactionObserver {
extension IAPManager{ extension IAPManager{
// func checkSubscriptionStatus(receiptInfo: [String: Any]) -> (isActive: Bool, isTrial: Bool, expiresDate: Date?) {
// // 首先检查 in_app 购买记录
// if let receipt = receiptInfo["receipt"] as? [String: Any],
// let inAppPurchases = receipt["in_app"] as? [[String: Any]] {
// // 检查是否存在永久商品购买记录
// let hasLifetimePurchase = inAppPurchases.contains { purchase in
// return purchase["product_id"] as? String == ProductID.lifetimeMember
// }
//
// if hasLifetimePurchase {
// print("检测到永久商品购买记录")
// return (true, false, nil)
// }
// }
//
// // 如果没有永久商品,继续检查订阅
// guard let latestReceiptInfo = receiptInfo["latest_receipt_info"] as? [[String: Any]] else {
// print("没有找到任何购买记录")
// return (false, false, nil)
// }
//
// // 按过期时间排序,确保获取最新的订阅记录
// let sortedReceipts = latestReceiptInfo.sorted { receipt1, receipt2 in
// let date1 = getExpiryDate(from: receipt1) ?? Date.distantPast
// let date2 = getExpiryDate(from: receipt2) ?? Date.distantPast
// return date1 > date2
// }
//
// guard let lastReceipt = sortedReceipts.first else {
// return (false, false, nil)
// }
//
// // 解析试用期状态
// let isTrial = (lastReceipt["is_trial_period"] as? String) == "true"
//
// // 获取过期时间
// let expiresDate = getExpiryDate(from: lastReceipt)
// let isActive = expiresDate?.compare(Date()) == .orderedDescending
//
// #if DEBUG
// if let expDate = expiresDate {
// let formatter = DateFormatter()
// formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
// print("订阅状态:\(isActive ? "已订阅" : "未订阅"),到期时间:\(formatter.string(from: expDate))")
// }
// #endif
//
// return (isActive, isTrial, expiresDate)
// }
func checkSubscriptionStatus(receiptInfo: [String: Any]) -> (isActive: Bool, isTrial: Bool, subscriptionType: SubscriptionType, expiresDate: Date?) { func checkSubscriptionStatus(receiptInfo: [String: Any]) -> (isActive: Bool, isTrial: Bool, subscriptionType: SubscriptionType, expiresDate: Date?) {
// 首先检查 in_app 购买记录 // 首先检查 in_app 购买记录
if let receipt = receiptInfo["receipt"] as? [String: Any], if let receipt = receiptInfo["receipt"] as? [String: Any],
......
//
// HttpRequest.swift
// Weather
//
// Created by apple on 2024/9/23.
//
import Foundation
struct HttpRequest{
static func getFormData<T:Codable>(to urlString: String, completion: @escaping (Result<T, Error>) -> Void) {
// 设置请求的 URL
guard let urlComponents = URLComponents(string: urlString) else {
completion(.failure(NSError(domain: "Invalid URL", code: 101, userInfo: nil)))
return
}
// 创建 URL 请求
guard let url = urlComponents.url else {
completion(.failure(NSError(domain: "Invalid URL Components", code: 102, userInfo: nil)))
return
}
// 创建 URLRequest 对象
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
print("请求地址",url.absoluteString)
// 执行网络请求
let session = URLSession.shared
let task = session.dataTask(with: request) { data, response, error in
// 处理错误
if let error = error {
print("Error in request: \(error.localizedDescription)")
DispatchQueue.main.async {
completion(.failure(error))
}
return
}
// 确保有数据返回
guard let data = data else {
print("No data returned")
DispatchQueue.main.async {
completion(.failure(NSError(domain: "No data returned", code: 103, userInfo: nil)))
}
return
}
// 解析响应(如果有的话)
do {
let model = try JSONDecoder().decode(T.self, from: data)
// print("请求数据",model)
DispatchQueue.main.async {
completion(.success(model))
}
} catch {
print("数据解析失败: \(error.localizedDescription)")
DispatchQueue.main.async {
completion(.failure(NSError(domain: "数据解析失败", code: 104, userInfo: nil)))
}
}
}
// 启动任务
task.resume()
}
static func postFormData(to urlString: String, parameters: [String: Any], completion: @escaping (Result<String, Error>) -> Void) {
// 设置请求的 URL
guard let urlComponents = URLComponents(string: urlString) else {
completion(.failure(NSError(domain: "Invalid URL", code: 101, userInfo: nil)))
return
}
// 创建 URL 请求
guard let url = urlComponents.url else {
completion(.failure(NSError(domain: "Invalid URL Components", code: 102, userInfo: nil)))
return
}
// 创建 URLRequest 对象
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// 将参数字典转换为 JSON 数据
do {
let jsonData = try JSONSerialization.data(withJSONObject: parameters, options: [])
request.httpBody = jsonData
} catch {
completion(.failure(NSError(domain: "参数序列化失败", code: 105, userInfo: nil)))
return
}
print("请求地址", url.absoluteString)
print("请求参数", parameters)
// 执行网络请求
let session = URLSession.shared
let task = session.dataTask(with: request) { data, response, error in
// 处理错误
if let error = error {
print("Error in request: \(error.localizedDescription)")
DispatchQueue.main.async {
completion(.failure(error))
}
return
}
// 确保有数据返回
guard let data = data else {
print("No data returned")
DispatchQueue.main.async {
completion(.failure(NSError(domain: "No data returned", code: 103, userInfo: nil)))
}
return
}
// 将返回的数据转换为字符串
if let jsonString = String(data: data, encoding: .utf8) {
DispatchQueue.main.async {
completion(.success(jsonString))
}
} else {
DispatchQueue.main.async {
completion(.failure(NSError(domain: "JSON转换字符串失败", code: 104, userInfo: nil)))
}
}
}
// 启动任务
task.resume()
}
static func postBodyWithString(to urlString: String, bodyValue: String, completion: @escaping (Result<String, Error>) -> Void) {
// 设置请求的 URL
guard let urlComponents = URLComponents(string: urlString) else {
completion(.failure(NSError(domain: "Invalid URL", code: 101, userInfo: nil)))
return
}
// 创建 URL 请求
guard let url = urlComponents.url else {
completion(.failure(NSError(domain: "Invalid URL Components", code: 102, userInfo: nil)))
return
}
// 创建 URLRequest 对象
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// 直接将字符串转换为Data
guard let data = bodyValue.data(using: .utf8) else {
completion(.failure(NSError(domain: "字符串转换Data失败", code: 105, userInfo: nil)))
return
}
request.httpBody = data
print("请求地址", url.absoluteString)
print("请求参数", bodyValue)
// 执行网络请求
let session = URLSession.shared
let task = session.dataTask(with: request) { data, response, error in
// 处理错误
if let error = error {
print("Error in request: \(error.localizedDescription)")
DispatchQueue.main.async {
completion(.failure(error))
}
return
}
// 确保有数据返回
guard let data = data else {
print("No data returned")
DispatchQueue.main.async {
completion(.failure(NSError(domain: "No data returned", code: 103, userInfo: nil)))
}
return
}
// 将返回的数据转换为字符串
if let jsonString = String(data: data, encoding: .utf8) {
DispatchQueue.main.async {
completion(.success(jsonString))
}
} else {
DispatchQueue.main.async {
completion(.failure(NSError(domain: "JSON转换字符串失败", code: 104, userInfo: nil)))
}
}
}
// 启动任务
task.resume()
}
}
import Foundation
// 顶层响应模型
struct ResponseModel<T: Codable>: Codable {
let status: Int
let msg: String
let sign: String
let result: ResultModel<T>
let enc: String?
let security: String
}
// 结果模型
struct ResultModel<T: Codable>: Codable {
let data: T
let extras: String?
}
\ No newline at end of file
...@@ -35,7 +35,8 @@ class ChargeViewController:BaseViewController { ...@@ -35,7 +35,8 @@ class ChargeViewController:BaseViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
APIReportManager.shared.startReport(type: .Charging_show)
titleView.addSubview(detailsBtn) titleView.addSubview(detailsBtn)
......
...@@ -101,6 +101,7 @@ class CompressController : BaseViewController { ...@@ -101,6 +101,7 @@ class CompressController : BaseViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
APIReportManager.shared.startReport(type: .Compress_show)
view.backgroundColor = .white view.backgroundColor = .white
self.navigationController?.navigationBar.isHidden = true self.navigationController?.navigationBar.isHidden = true
getViewData() getViewData()
......
...@@ -30,7 +30,7 @@ class ContactViewController : BaseViewController { ...@@ -30,7 +30,7 @@ class ContactViewController : BaseViewController {
}() }()
override func viewDidLoad() { override func viewDidLoad() {
APIReportManager.shared.startReport(type: .Contacts_show)
self.view.backgroundColor = .white self.view.backgroundColor = .white
self.view.addSubview(self.navView) self.view.addSubview(self.navView)
......
...@@ -322,6 +322,7 @@ class HomeInfoViewController:BaseViewController { ...@@ -322,6 +322,7 @@ class HomeInfoViewController:BaseViewController {
self.setDefaultPage() self.setDefaultPage()
} }
configSelectAll()
} }
...@@ -442,6 +443,14 @@ class HomeInfoViewController:BaseViewController { ...@@ -442,6 +443,14 @@ class HomeInfoViewController:BaseViewController {
} }
} }
func configSelectAll(){
seletedAllBtn.isSelected = true
self.seletedAllBtn.width = seletedAllBtn.isSelected ? 131 : 115
seletedAllBtn.x = titleView.width - marginLR - seletedAllBtn.width
tablewView.changeALlValue(isSeleted: seletedAllBtn.isSelected)
}
@objc func seletedAllBtnClick() { @objc func seletedAllBtnClick() {
DispatchQueue.main.async {[weak self] in DispatchQueue.main.async {[weak self] in
......
...@@ -115,7 +115,7 @@ class HomeViewController:BaseViewController { ...@@ -115,7 +115,7 @@ class HomeViewController:BaseViewController {
self.setupUI() self.setupUI()
// 调用下追踪权限 // 调用下追踪权限
checkTrackingAuthorization() // checkTrackingAuthorization()
homeView = HomeView(frame: view.bounds) homeView = HomeView(frame: view.bounds)
homeView?.y = cWindow?.safeAreaInsets.top ?? 20 homeView?.y = cWindow?.safeAreaInsets.top ?? 20
...@@ -126,6 +126,11 @@ class HomeViewController:BaseViewController { ...@@ -126,6 +126,11 @@ class HomeViewController:BaseViewController {
guard let model = model else{ return } guard let model = model else{ return }
DispatchQueue.main.async { DispatchQueue.main.async {
let vc:HomeInfoViewController = HomeInfoViewController(ids: model.assets , type: type,titleText: model.folderName) let vc:HomeInfoViewController = HomeInfoViewController(ids: model.assets , type: type,titleText: model.folderName)
if model.folderName == HomeUIEnum.Dublicates.title{
APIReportManager.shared.startReport(type: .Duplicates_show)
}else{
APIReportManager.shared.startReport(type: .Similar_show)
}
self.navigationController?.pushViewController(vc, animated: true) self.navigationController?.pushViewController(vc, animated: true)
} }
} }
...@@ -135,6 +140,7 @@ class HomeViewController:BaseViewController { ...@@ -135,6 +140,7 @@ class HomeViewController:BaseViewController {
if otherItemRow == 0 { if otherItemRow == 0 {
DispatchQueue.main.async { DispatchQueue.main.async {
let vc:HomeVideoDetailController = HomeVideoDetailController() let vc:HomeVideoDetailController = HomeVideoDetailController()
APIReportManager.shared.startReport(type: .Videos_show)
self.navigationController?.pushViewController(vc, animated: true) self.navigationController?.pushViewController(vc, animated: true)
} }
} }
...@@ -142,12 +148,14 @@ class HomeViewController:BaseViewController { ...@@ -142,12 +148,14 @@ class HomeViewController:BaseViewController {
if otherItemRow == 1 { if otherItemRow == 1 {
DispatchQueue.main.async { DispatchQueue.main.async {
let vc:HomeInfoViewController = HomeInfoViewController(ids: model.assets , type: .similarScreenshots ,titleText: model.folderName) let vc:HomeInfoViewController = HomeInfoViewController(ids: model.assets , type: .similarScreenshots ,titleText: model.folderName)
APIReportManager.shared.startReport(type: .SimilarScreenshots_show)
self.navigationController?.pushViewController(vc, animated: true) self.navigationController?.pushViewController(vc, animated: true)
} }
} }
if otherItemRow == 3 { if otherItemRow == 3 {
DispatchQueue.main.async { DispatchQueue.main.async {
let vc:HomeInfoViewController = HomeInfoViewController(ids: model.assets , type: .SimilarVideos ,titleText: model.folderName) let vc:HomeInfoViewController = HomeInfoViewController(ids: model.assets , type: .SimilarVideos ,titleText: model.folderName)
APIReportManager.shared.startReport(type: .SimilarVideos_show)
self.navigationController?.pushViewController(vc, animated: true) self.navigationController?.pushViewController(vc, animated: true)
} }
} }
...@@ -155,6 +163,11 @@ class HomeViewController:BaseViewController { ...@@ -155,6 +163,11 @@ class HomeViewController:BaseViewController {
if otherItemRow == 2 || otherItemRow == 4{ if otherItemRow == 2 || otherItemRow == 4{
DispatchQueue.main.async { DispatchQueue.main.async {
let vc = HomePhotosDetailViewController(mediaType: otherItemRow == 2 ? .screenshots : .Other) let vc = HomePhotosDetailViewController(mediaType: otherItemRow == 2 ? .screenshots : .Other)
if otherItemRow == 2{
APIReportManager.shared.startReport(type: .Screenshots_show)
}else{
APIReportManager.shared.startReport(type: .Other_show)
}
self.navigationController?.pushViewController(vc, animated: true) self.navigationController?.pushViewController(vc, animated: true)
} }
} }
...@@ -224,6 +237,7 @@ class HomeViewController:BaseViewController { ...@@ -224,6 +237,7 @@ class HomeViewController:BaseViewController {
let nav:BaseNavViewController = BaseNavViewController(rootViewController: vc) let nav:BaseNavViewController = BaseNavViewController(rootViewController: vc)
nav.modalPresentationStyle = .fullScreen nav.modalPresentationStyle = .fullScreen
self.present(nav, animated: true) self.present(nav, animated: true)
break
case .lifetime,.year: case .lifetime,.year:
let vc : PayCompletedViewController = PayCompletedViewController() let vc : PayCompletedViewController = PayCompletedViewController()
vc.modalPresentationStyle = .fullScreen vc.modalPresentationStyle = .fullScreen
...@@ -292,6 +306,7 @@ extension HomeViewController { ...@@ -292,6 +306,7 @@ extension HomeViewController {
case .authorized: case .authorized:
// 用户已授权跟踪 // 用户已授权跟踪
print("用户已授权应用进行跟踪") print("用户已授权应用进行跟踪")
Print("idfa",AdvManager.shared.getIDFA())
case .denied: case .denied:
// 用户拒绝了跟踪请求 // 用户拒绝了跟踪请求
print("用户拒绝了应用的跟踪请求") print("用户拒绝了应用的跟踪请求")
...@@ -317,6 +332,7 @@ extension HomeViewController { ...@@ -317,6 +332,7 @@ extension HomeViewController {
case .authorized: case .authorized:
// 用户已授权跟踪 // 用户已授权跟踪
print("用户已授权应用进行跟踪") print("用户已授权应用进行跟踪")
Print("idfa",AdvManager.shared.getIDFA())
case .denied: case .denied:
// 用户拒绝了跟踪请求 // 用户拒绝了跟踪请求
print("用户拒绝了应用的跟踪请求") print("用户拒绝了应用的跟踪请求")
......
...@@ -315,6 +315,7 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol ...@@ -315,6 +315,7 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
let model = viewModel.cardGroup[indexPath.row] //model?.otherModelArray[indexPath.row] let model = viewModel.cardGroup[indexPath.row] //model?.otherModelArray[indexPath.row]
return itemWidth + 12 + UILabel.getSizeWith(font: UIFont.systemFont(ofSize: 16, weight: .bold),lineSpacing: 5, width: itemWidth - 32, numberOfLines: 0, content: model.folderName).height return itemWidth + 12 + UILabel.getSizeWith(font: UIFont.systemFont(ofSize: 16, weight: .bold),lineSpacing: 5, width: itemWidth - 32, numberOfLines: 0, content: model.folderName).height
} }
} }
......
...@@ -205,7 +205,9 @@ extension HomeTitleCollectionCell:UICollectionViewDelegate,UICollectionViewDataS ...@@ -205,7 +205,9 @@ extension HomeTitleCollectionCell:UICollectionViewDelegate,UICollectionViewDataS
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// 计算 cell 宽度 // 计算 cell 宽度
return CGSize(width:collectionView.height - 18, height: collectionView.height - 18) // 宽高相等,形成网格 let width = max(0, collectionView.height - 18) // 使用实际的宽度计算方法
let height = max(0,collectionView.height - 18) // 使用实际的高度计算方法
return CGSize(width:width, height: height) // 宽高相等,形成网格
} }
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
......
...@@ -215,12 +215,14 @@ extension HomeVideoCoverCell{ ...@@ -215,12 +215,14 @@ extension HomeVideoCoverCell{
playerLayer.isHidden = false playerLayer.isHidden = false
if videoURL == videoUrl{ if videoURL == videoUrl{
Print("地址相同,无需刷新") // Print("地址相同,无需刷新")
return return
} }
videoUrl = videoURL videoUrl = videoURL
Print("地址不同,需刷新") // if videoPlayer
// Print("地址不同,需刷新")
let item = AVPlayerItem.init(url: videoURL) let item = AVPlayerItem.init(url: videoURL)
......
...@@ -58,7 +58,7 @@ class MaintaiDetailViewController: BaseViewController { ...@@ -58,7 +58,7 @@ class MaintaiDetailViewController: BaseViewController {
} }
removeBtn = UIButton() removeBtn = UIButton()
removeBtn.setTitle("Un-keep All", for: .normal) removeBtn.setTitle("Not-keep All", for: .normal)
removeBtn.addTarget(self, action: #selector(removeAll), for: .touchUpInside) removeBtn.addTarget(self, action: #selector(removeAll), for: .touchUpInside)
removeBtn.setTitleColor(.black, for: .normal) removeBtn.setTitleColor(.black, for: .normal)
removeBtn.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .semibold) removeBtn.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .semibold)
...@@ -210,25 +210,16 @@ extension MaintaiDetailViewController:UITableViewDelegate,UITableViewDataSource{ ...@@ -210,25 +210,16 @@ extension MaintaiDetailViewController:UITableViewDelegate,UITableViewDataSource{
return cell return cell
} }
if viewModel.souces[indexPath.row].first?.mediaType == 1,viewModel.souces[indexPath.row].count == 1{
let cell = tableView.dequeueReusableCell(withIdentifier: "MaintaiDetailPicCell") as! MaintaiDetailPicCell
cell.model = viewModel.souces[indexPath.row].first
cell.selectBtn.isSelected = selectAsset.contains(viewModel.souces[indexPath.row])
cell.selectChangeBlock = {[weak self] in
guard let weakSelf = self else { return }
weakSelf.dealPickAssetModel(index: indexPath.row)
weakSelf.tableView.reloadData()
}
return cell
}
let cell = tableView.dequeueReusableCell(withIdentifier: "MaintaiDetialVideoCell") as! MaintaiDetialVideoCell let cell = tableView.dequeueReusableCell(withIdentifier: "MaintaiDetialVideoCell") as! MaintaiDetialVideoCell
cell.model = viewModel.souces[indexPath.row].first cell.model = viewModel.souces[indexPath.row].first
cell.selectBtn.isSelected = selectAsset.contains(viewModel.souces[indexPath.row]) cell.selectBtn.isSelected = selectAsset.contains(viewModel.souces[indexPath.row])
cell.selectChangeBlock = {[weak self] in cell.selectChangeBlock = {[weak self] in
guard let weakSelf = self else { return } guard let weakSelf = self else { return }
weakSelf.dealPickAssetModel(index: indexPath.row) weakSelf.dealPickAssetModel(index: indexPath.row)
weakSelf.tableView.reloadData() // 不要刷新整个cell,只更新选中状态
if let current = tableView.cellForRow(at: indexPath) as? MaintaiDetialVideoCell{
current.selectBtn.isSelected = weakSelf.selectAsset.contains(weakSelf.viewModel.souces[indexPath.row])
}
} }
return cell return cell
......
...@@ -54,7 +54,7 @@ class MaintainViewListController: BaseViewController { ...@@ -54,7 +54,7 @@ class MaintainViewListController: BaseViewController {
} }
removeBtn = UIButton() removeBtn = UIButton()
removeBtn.setTitle("Un-keep All", for: .normal) removeBtn.setTitle("Not-keep All", for: .normal)
removeBtn.addTarget(self, action: #selector(removeAll), for: .touchUpInside) removeBtn.addTarget(self, action: #selector(removeAll), for: .touchUpInside)
removeBtn.setTitleColor(.black, for: .normal) removeBtn.setTitleColor(.black, for: .normal)
removeBtn.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .semibold) removeBtn.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .semibold)
......
...@@ -40,7 +40,7 @@ class MaintaiDetailImageSmallCell: UICollectionViewCell { ...@@ -40,7 +40,7 @@ class MaintaiDetailImageSmallCell: UICollectionViewCell {
selectBtn.setImage(UIImage.init(named: "icon_maintai_unselect_small"), for: .normal) selectBtn.setImage(UIImage.init(named: "icon_maintai_unselect_small"), for: .normal)
selectBtn.setImage(UIImage.init(named: "icon_maintai_select_small"), for: .selected) selectBtn.setImage(UIImage.init(named: "icon_maintai_select_small"), for: .selected)
addSubview(selectBtn) addSubview(selectBtn)
selectBtn.addTarget(self, action: #selector(selectChange), for: .touchUpInside) // selectBtn.addTarget(self, action: #selector(selectChange), for: .touchUpInside)
selectBtn.snp.makeConstraints { make in selectBtn.snp.makeConstraints { make in
make.right.bottom.equalTo(0) make.right.bottom.equalTo(0)
make.size.equalTo(30) make.size.equalTo(30)
...@@ -54,7 +54,7 @@ class MaintaiDetailImageSmallCell: UICollectionViewCell { ...@@ -54,7 +54,7 @@ class MaintaiDetailImageSmallCell: UICollectionViewCell {
} }
@objc func selectChange(){ @objc func selectChange(){
selectChangeBlock?() // selectChangeBlock?()
} }
} }
...@@ -75,6 +75,10 @@ class MaintaiDetailTableViewCell: UITableViewCell { ...@@ -75,6 +75,10 @@ class MaintaiDetailTableViewCell: UITableViewCell {
} }
deinit{
Print("释放图像cell",self)
}
} }
extension MaintaiDetailTableViewCell:UICollectionViewDelegate,UICollectionViewDataSource{ extension MaintaiDetailTableViewCell:UICollectionViewDelegate,UICollectionViewDataSource{
...@@ -96,13 +100,19 @@ extension MaintaiDetailTableViewCell:UICollectionViewDelegate,UICollectionViewDa ...@@ -96,13 +100,19 @@ extension MaintaiDetailTableViewCell:UICollectionViewDelegate,UICollectionViewDa
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MaintaiDetailImageSmallCell", for: indexPath) as! MaintaiDetailImageSmallCell let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MaintaiDetailImageSmallCell", for: indexPath) as! MaintaiDetailImageSmallCell
cell.model = source[indexPath.row] cell.model = source[indexPath.row]
cell.selectBtn.isSelected = selectAsset.contains(source[indexPath.row]) cell.selectBtn.isSelected = selectAsset.contains(source[indexPath.row])
cell.selectChangeBlock = {[weak self] in // cell.selectChangeBlock = {[weak self] in
guard let weakSelf = self else { return } // guard let weakSelf = self else { return }
weakSelf.dealSelect(model: weakSelf.source[indexPath.row]) // weakSelf.dealSelect(model: weakSelf.source[indexPath.row])
} // }
return cell return cell
} }
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath){
if collectionView == pageCollectionView{
dealSelect(model: source[indexPath.row])
}
}
func dealSelect(model:AssetModel){ func dealSelect(model:AssetModel){
...@@ -122,6 +132,7 @@ extension MaintaiDetailTableViewCell:UICollectionViewDelegate,UICollectionViewDa ...@@ -122,6 +132,7 @@ extension MaintaiDetailTableViewCell:UICollectionViewDelegate,UICollectionViewDa
selectCallBack?(selectAsset) selectCallBack?(selectAsset)
} }
} }
extension MaintaiDetailTableViewCell:UIScrollViewDelegate{ extension MaintaiDetailTableViewCell:UIScrollViewDelegate{
...@@ -191,4 +202,6 @@ extension MaintaiDetailTableViewCell:UIScrollViewDelegate{ ...@@ -191,4 +202,6 @@ extension MaintaiDetailTableViewCell:UIScrollViewDelegate{
self.mainCollectionView.contentOffset = CGPoint(x: index * Int(self.bigW), y: 0) self.mainCollectionView.contentOffset = CGPoint(x: index * Int(self.bigW), y: 0)
draggView = .null draggView = .null
} }
} }
...@@ -10,17 +10,12 @@ import AVKit ...@@ -10,17 +10,12 @@ import AVKit
class MaintaiDetialVideoCell: UITableViewCell { class MaintaiDetialVideoCell: UITableViewCell {
// private var player: AVPlayer?
// private var playerLayer: AVPlayerLayer?
var selectBtn:UIButton! var selectBtn:UIButton!
var selectChangeBlock:(() ->Void)? var selectChangeBlock:(() ->Void)?
// var videoPath:String?{ var playerLayer:AVPlayerLayer!
// didSet{
// setPlayerInfo()
// }
// }
override func awakeFromNib() { override func awakeFromNib() {
super.awakeFromNib() super.awakeFromNib()
...@@ -44,6 +39,8 @@ class MaintaiDetialVideoCell: UITableViewCell { ...@@ -44,6 +39,8 @@ class MaintaiDetialVideoCell: UITableViewCell {
} }
private func setupPlayer() { private func setupPlayer() {
playerLayer = AVPlayerLayer.init(player: videoPlayer)
playerLayer.backgroundColor = UIColor.black.cgColor
contentView.layer.addSublayer(playerLayer) contentView.layer.addSublayer(playerLayer)
} }
...@@ -76,28 +73,18 @@ class MaintaiDetialVideoCell: UITableViewCell { ...@@ -76,28 +73,18 @@ class MaintaiDetialVideoCell: UITableViewCell {
}() }()
lazy var playerLayer:AVPlayerLayer = {
let playerLayer = AVPlayerLayer.init(player: videoPlayer)
playerLayer.backgroundColor = UIColor.black.cgColor
return playerLayer
}()
func configure(with videoURL: URL?) { func configure(with videoURL: URL?) {
guard let videoURL = videoURL else{ guard let videoURL = videoURL else{
videoPlayer.pause() videoPlayer.pause()
return return
} }
Print("视频url",videoURL)
if videoPlayer.rate != 0{
return
}
let item = AVPlayerItem.init(url: videoURL) let item = AVPlayerItem.init(url: videoURL)
videoPlayer.replaceCurrentItem(with: item) videoPlayer.replaceCurrentItem(with: item)
videoPlayer.play() videoPlayer.play()
NotificationCenter.default.addObserver(self, NotificationCenter.default.addObserver(self,
...@@ -107,17 +94,20 @@ class MaintaiDetialVideoCell: UITableViewCell { ...@@ -107,17 +94,20 @@ class MaintaiDetialVideoCell: UITableViewCell {
} }
@objc private func playerDidFinishPlaying() { @objc private func playerDidFinishPlaying() {
videoPlayer.seek(to: .zero) videoPlayer.seek(to: .zero)
videoPlayer.play() videoPlayer.play()
} }
@objc func selectChange(){ @objc func selectChange(){
selectChangeBlock?() selectChangeBlock?()
} }
deinit{ deinit{
print("释放",self)
// 停止播放
videoPlayer.pause()
videoPlayer.replaceCurrentItem(with: nil)
// 移除观察者
NotificationCenter.default.removeObserver(self) NotificationCenter.default.removeObserver(self)
} }
} }
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
import UIKit import UIKit
import Lottie import Lottie
import Foundation import Foundation
import AppTrackingTransparency
class PermissionVC:UIViewController { class PermissionVC:UIViewController {
...@@ -37,15 +38,15 @@ class PermissionVC:UIViewController { ...@@ -37,15 +38,15 @@ class PermissionVC:UIViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
view.backgroundColor = .white view.backgroundColor = .white
checkTrackingAuthorization()
setupUI() setupUI()
} }
override func viewDidAppear(_ animated: Bool) { override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
isPPClick = false isPPClick = false
...@@ -244,3 +245,61 @@ extension PermissionVC: UITextViewDelegate { ...@@ -244,3 +245,61 @@ extension PermissionVC: UITextViewDelegate {
return false return false
} }
} }
extension PermissionVC {
// 检查跟踪授权状态
func checkTrackingAuthorization() {
if #available(iOS 14, *) {
let status = ATTrackingManager.trackingAuthorizationStatus
switch status {
case .authorized:
// 用户已授权跟踪
print("用户已授权应用进行跟踪")
Print("idfa",AdvManager.shared.getIDFA())
case .denied:
// 用户拒绝了跟踪请求
print("用户拒绝了应用的跟踪请求")
case .restricted:
// 由于系统限制,无法跟踪用户
print("由于系统限制,无法跟踪用户")
case .notDetermined:
// 用户尚未对跟踪请求做出决定
print("用户尚未对跟踪请求做出决定,再次请求授权")
requestTrackingAuthorization()
@unknown default:
break
}
} else {
// iOS 14 以下系统不支持 ATT 框架
// 可以执行其他操作
}
}
func requestTrackingAuthorization() {
if #available(iOS 14, *) {
ATTrackingManager.requestTrackingAuthorization(completionHandler: { status in
switch status {
case .authorized:
// 用户已授权跟踪
print("用户已授权应用进行跟踪")
Print("idfa",AdvManager.shared.getIDFA())
case .denied:
// 用户拒绝了跟踪请求
print("用户拒绝了应用的跟踪请求")
case .restricted:
// 由于系统限制,无法跟踪用户
print("由于系统限制,无法跟踪用户")
case .notDetermined:
// 用户尚未对跟踪请求做出决定
print("用户尚未对跟踪请求做出决定")
@unknown default:
break
}
})
} else {
// iOS 14 以下系统不支持 ATT 框架
// 可以执行其他操作
}
}
}
...@@ -130,17 +130,20 @@ extension HomePayViewController { ...@@ -130,17 +130,20 @@ extension HomePayViewController {
} }
private func payTouch() -> Void { private func payTouch() -> Void {
IAPManager.share.purchase((homePayView?.type == 0) ? .weekSubscribe : .nonConsumable) {[weak self] result in let subscribe:PayState = homePayView?.type == 0 ? .weekSubscribe : .nonConsumable
IAPManager.share.purchase(subscribe) {[weak self] result in
guard let weakSelf = self else { return } guard let weakSelf = self else { return }
switch result { switch result {
case .success(let success): case .success(let success):
Print("内购成功",success) Print("内购成功",success)
DispatchQueue.main.async { APIReportManager.shared.startReport(type: .apple_billing_success, ext: ["productId":subscribe.productId,"from":IAPManager.share.currentVCName])
DispatchQueue.main.async {
SVProgressHUD.showSuccess(withStatus: "purchase succeeds") SVProgressHUD.showSuccess(withStatus: "purchase succeeds")
weakSelf.dismiss(animated: true) weakSelf.dismiss(animated: true)
} }
case .failure(let failure): case .failure(let failure):
Print("内购失败",failure) Print("内购失败",failure)
APIReportManager.shared.startReport(type: .apple_billing_error, ext: ["productId":subscribe.productId,"info":failure.localizedDescription,"from":IAPManager.share.currentVCName])
DispatchQueue.main.async { DispatchQueue.main.async {
SVProgressHUD.showError(withStatus: failure.localizedDescription) SVProgressHUD.showError(withStatus: failure.localizedDescription)
} }
...@@ -180,6 +183,9 @@ extension HomePayViewController { ...@@ -180,6 +183,9 @@ extension HomePayViewController {
let nav:BaseNavViewController = BaseNavViewController(rootViewController: vc) let nav:BaseNavViewController = BaseNavViewController(rootViewController: vc)
nav.modalPresentationStyle = .fullScreen nav.modalPresentationStyle = .fullScreen
guard let rt = UIViewController.topMostViewController() else { return } guard let rt = UIViewController.topMostViewController() else { return }
// Print(rt.class)
let className = NSStringFromClass(type(of: rt))
IAPManager.share.currentVCName = className
rt.present(nav, animated: true) rt.present(nav, animated: true)
} }
......
...@@ -57,7 +57,7 @@ class PayDistanceViewController: UIViewController { ...@@ -57,7 +57,7 @@ class PayDistanceViewController: UIViewController {
let distanceL = UILabel() let distanceL = UILabel()
distanceL.text = "70% Discount" distanceL.text = "50% Discount"
distanceL.font = UIFont.systemFont(ofSize: 40, weight: .semibold) distanceL.font = UIFont.systemFont(ofSize: 40, weight: .semibold)
distanceL.textColor = UIColor.colorWithHex(hexStr: "#111111") distanceL.textColor = UIColor.colorWithHex(hexStr: "#111111")
scrollView.addSubview(distanceL) scrollView.addSubview(distanceL)
...@@ -74,12 +74,6 @@ class PayDistanceViewController: UIViewController { ...@@ -74,12 +74,6 @@ class PayDistanceViewController: UIViewController {
yearDistacePrice.text = ""//"$39.99 $19.99 / Year" yearDistacePrice.text = ""//"$39.99 $19.99 / Year"
scrollView.addSubview(yearDistacePrice) scrollView.addSubview(yearDistacePrice)
// let priceAtt = createRichPriceText(
// originalPrice: "$39.99",
// discountedPrice: "$19.99 / Year"
// )
// yearDistacePrice.attributedText = priceAtt
let cancelLabel = UILabel() let cancelLabel = UILabel()
cancelLabel.font = UIFont.systemFont(ofSize: 12,weight: .semibold) cancelLabel.font = UIFont.systemFont(ofSize: 12,weight: .semibold)
cancelLabel.textColor = UIColor.colorWithHex(hexStr: "#0082FF") cancelLabel.textColor = UIColor.colorWithHex(hexStr: "#0082FF")
......
...@@ -53,6 +53,7 @@ class SecretViewController: BaseViewController { ...@@ -53,6 +53,7 @@ class SecretViewController: BaseViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
APIReportManager.shared.startReport(type: .SecretSpace_show)
_ = Resource.isDirect() _ = Resource.isDirect()
if isShow { if isShow {
self.ShowUI() self.ShowUI()
......
...@@ -195,6 +195,9 @@ extension TrashViewController:UIScrollViewDelegate{ ...@@ -195,6 +195,9 @@ extension TrashViewController:UIScrollViewDelegate{
let data : [AssetModel] = TrashDataManager.getCurrentMediaTypeTrashData(mediaType: info.0) let data : [AssetModel] = TrashDataManager.getCurrentMediaTypeTrashData(mediaType: info.0)
let type : TrashTypeEnum = info.0 let type : TrashTypeEnum = info.0
DispatchQueue.main.async { DispatchQueue.main.async {
if self.delBtn == nil{
return
}
if data.count <= 0{ if data.count <= 0{
self.delBtn.setTitle("Delete", for: .normal) self.delBtn.setTitle("Delete", for: .normal)
self.delBtn.backgroundColor = UIColor(red: 0.6, green: 0.6, blue: 0.6, alpha: 1) self.delBtn.backgroundColor = UIColor(red: 0.6, green: 0.6, blue: 0.6, alpha: 1)
......
...@@ -28,19 +28,23 @@ class TrashContenAssetCell: UICollectionViewCell { ...@@ -28,19 +28,23 @@ class TrashContenAssetCell: UICollectionViewCell {
var model:AssetModel?{ var model:AssetModel?{
didSet{ didSet{
guard let model = model else{return} guard let model = model else{return}
if self.mediaType == .video { let image = self.mediaType == .video ? "videosmoren" : "photosmoren"
PhotoAndVideoMananger.mananger.getPreImageFromVideo(identifier: model.localIdentifier, completed: { [weak self] image in self.assetImage.asset.load(withLocalIdentifier: model.localIdentifier,placeholder: UIImage.init(named: image))
guard let self else {return}
DispatchQueue.main.async { // if self.mediaType == .video {
self.assetImage.image = image // PhotoAndVideoMananger.mananger.getPreImageFromVideo(identifier: model.localIdentifier, completed: { [weak self] image in
} // guard let self else {return}
}) // DispatchQueue.main.async {
}else { // self.assetImage.image = image
DispatchQueue.main.async { // }
self.assetImage.image = PhotoAndVideoMananger.mananger.getImageFromAssetID(id: model.localIdentifier) // })
} // }else {
} // DispatchQueue.main.async {
// self.assetImage.image = PhotoAndVideoMananger.mananger.getImageFromAssetID(id: model.localIdentifier)
// }
// }
} }
} }
......
...@@ -70,7 +70,7 @@ class TrashContenView: UIView { ...@@ -70,7 +70,7 @@ class TrashContenView: UIView {
layout.minimumInteritemSpacing = 12 layout.minimumInteritemSpacing = 12
layout.minimumLineSpacing = 12 layout.minimumLineSpacing = 12
layout.sectionInset = UIEdgeInsets(top: 20, left: 16, bottom: 0, right: 16) layout.sectionInset = UIEdgeInsets(top: 20, left: 16, bottom: 0, right: 16)
layout.itemSize = CGSize(width: (ScreenW-56)/3, height: (ScreenW-56)/3) layout.itemSize = CGSize(width: Int((ScreenW-56)/3), height: Int((ScreenW-56)/3))
collectionView = UICollectionView.init(frame: CGRect.zero,collectionViewLayout: layout) collectionView = UICollectionView.init(frame: CGRect.zero,collectionViewLayout: layout)
collectionView.delegate = self collectionView.delegate = self
collectionView.backgroundColor = UIColor.colorWithHex(hexStr: "#F2F6FC") collectionView.backgroundColor = UIColor.colorWithHex(hexStr: "#F2F6FC")
......
...@@ -93,3 +93,20 @@ func GETCURRENTNAV() -> UINavigationController? { ...@@ -93,3 +93,20 @@ func GETCURRENTNAV() -> UINavigationController? {
let rt = k?.rootViewController let rt = k?.rootViewController
return (pre as? UINavigationController) ?? ((rt as? UITabBarController)?.selectedViewController as? UINavigationController) ?? (rt as? UINavigationController) return (pre as? UINavigationController) ?? ((rt as? UITabBarController)?.selectedViewController as? UINavigationController) ?? (rt as? UINavigationController)
} }
func GETCURRENTVC() -> UIViewController? {
let k = UIApplication.shared.windows.filter({$0.isKeyWindow}).first
let pre = k?.rootViewController?.presentedViewController
let rt = k?.rootViewController
return pre ?? ((rt as? UITabBarController)?.selectedViewController) ?? rt
}
func GETCURRENTVCNAME() -> String {
guard let currentVC = GETCURRENTVC() else { return "" }
let className = NSStringFromClass(type(of: currentVC))
// 如果需要去掉模块名,可以用下面这行
// return className.components(separatedBy: ".").last ?? className
return className
}
...@@ -13,11 +13,15 @@ class UserDef:NSObject { ...@@ -13,11 +13,15 @@ class UserDef:NSObject {
var isShowLanding:Bool = false var isShowLanding:Bool = false
var isFirstStart:Bool = true
override init() { override init() {
let defaults:UserDefaults = UserDefaults.standard let defaults:UserDefaults = UserDefaults.standard
self.isShowLanding = defaults.value(forKey: "isShowLanding") as? Bool ?? false self.isShowLanding = defaults.value(forKey: "isShowLanding") as? Bool ?? false
self.isFirstStart = defaults.value(forKey: "isFirstStart") as? Bool ?? true
} }
func saveUserDefToSandBox() { func saveUserDefToSandBox() {
...@@ -29,6 +33,16 @@ class UserDef:NSObject { ...@@ -29,6 +33,16 @@ class UserDef:NSObject {
defaults.synchronize() defaults.synchronize()
} }
func saveFirstStart(){
let defaults:UserDefaults = UserDefaults.standard
defaults.setValue(false, forKey: "isFirstStart")
defaults.synchronize()
}
class func saveKeyWithValue(key:String,value:Any) { class func saveKeyWithValue(key:String,value:Any) {
UserDefaults.standard.set(value, forKey: key) UserDefaults.standard.set(value, forKey: key)
......
...@@ -18,6 +18,7 @@ target 'PhoneManager' do ...@@ -18,6 +18,7 @@ target 'PhoneManager' do
# pod 'GoogleSignIn' # pod 'GoogleSignIn'
pod 'MJRefresh' , '3.7.9' pod 'MJRefresh' , '3.7.9'
pod 'GoogleAPIClientForREST/Gmail' pod 'GoogleAPIClientForREST/Gmail'
pod 'Adjust', '~> 5.4.0'
post_install do |installer| post_install do |installer|
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment