1363 lines
50 KiB
Swift
1363 lines
50 KiB
Swift
//
|
||
// YL_NetWorkManager.swift
|
||
// wallpaper_project
|
||
// Created by 忆海16 on 2024/9/29.
|
||
//
|
||
|
||
import Foundation
|
||
import UIKit
|
||
import AdSupport
|
||
import CoreTelephony
|
||
import Network
|
||
import SystemConfiguration
|
||
import AVFoundation
|
||
import OpenGLES
|
||
import AppTrackingTransparency
|
||
import CommonCrypto
|
||
|
||
|
||
/// <#Description#>
|
||
class YL_NetWorkManager{
|
||
static var kBaseUrl = YL_NetWorkManager.bFaceLocalUrl()
|
||
|
||
static var kURL_AD_Start = "/top_selection/save_app_start_log"
|
||
static var kURL_AD_Load = "/top_selection/save_ad_load_log"
|
||
static var kURL_AD_Show = "/top_selection/save_ad_show_log"
|
||
static var kURL_save_logs = "/ios/top_selection/save_iphone_logs"
|
||
|
||
var ipLoadTime: DispatchTime?
|
||
|
||
static var kLocalBaseUrl = BbbAdManager.config.adbrush_local_url
|
||
|
||
|
||
static var kLocalUrlStr: (String) -> String {
|
||
return { path in
|
||
return "\(self.kLocalBaseUrl)/\(path)"
|
||
}
|
||
}
|
||
|
||
|
||
static func bFaceLocalUrl() -> String {
|
||
|
||
return BbbAdManager.config.adbrush_base_url
|
||
|
||
}
|
||
|
||
|
||
|
||
typealias LuxNetManagerCallback = (Error?, Bool, [String: Any]?) -> Void
|
||
|
||
|
||
|
||
static func uploadData(mdic: [String: Any], urlPath: String, callback: @escaping (Error?, Bool, [String: Any]?) -> Void) {
|
||
guard let url = URL(string: urlPath) else {
|
||
print("Invalid URL")
|
||
return
|
||
}
|
||
|
||
print("---------mdic \(mdic)")
|
||
|
||
print("---------urlPath\(urlPath)")
|
||
|
||
var request = URLRequest(url: url)
|
||
request.httpMethod = "POST"
|
||
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||
|
||
do {
|
||
let data = try JSONSerialization.data(withJSONObject: mdic, options: [])
|
||
request.httpBody = data
|
||
} catch {
|
||
print("Error serializing JSON: \(error.localizedDescription)")
|
||
|
||
|
||
DispatchQueue.main.async {
|
||
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: [
|
||
"text":"Error serializing JSON: \(error.localizedDescription)"
|
||
])
|
||
}
|
||
|
||
return
|
||
}
|
||
|
||
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
|
||
if let error = error {
|
||
callback(error, false, nil)
|
||
print("Network error: \(error.localizedDescription)")
|
||
DispatchQueue.main.async {
|
||
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: [
|
||
"text":"Network error: \(error.localizedDescription)"
|
||
])
|
||
}
|
||
} else {
|
||
guard let data = data else {
|
||
callback(nil, false, nil)
|
||
print("No data received")
|
||
DispatchQueue.main.async {
|
||
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: [
|
||
"text":"No data received"
|
||
])
|
||
}
|
||
return
|
||
}
|
||
|
||
do {
|
||
if let result = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
||
print("Server response: \(result)")
|
||
callback(nil, true, result)
|
||
|
||
DispatchQueue.main.async {
|
||
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: [
|
||
"text":"Server response: \(result)"
|
||
])
|
||
}
|
||
|
||
}
|
||
} catch {
|
||
callback(error, false, nil)
|
||
|
||
DispatchQueue.main.async {
|
||
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: [
|
||
"text":"Error parsing response JSON: \(error.localizedDescription)"
|
||
])
|
||
}
|
||
|
||
|
||
|
||
print("Error parsing response JSON: \(error.localizedDescription)")
|
||
}
|
||
}
|
||
}
|
||
|
||
task.resume()
|
||
}
|
||
|
||
|
||
// 请求远程IP
|
||
func requestRemoteIp() {
|
||
ipLoadTime = DispatchTime.now()
|
||
|
||
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "获取ip中..."])
|
||
|
||
guard let url = URL(string: "https://openapi.lux-ad.com/app/common/getIPInfo") else { return }
|
||
let request = URLRequest(url: url)
|
||
let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
||
if let error = error {
|
||
print("解析ip失败....")
|
||
DispatchQueue.main.async {
|
||
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "解析ip失败...."])
|
||
}
|
||
return
|
||
}
|
||
|
||
guard let data = data,
|
||
let result = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
||
let ip = result["data"] as? [String: Any],
|
||
let ipAddress = ip["ip"] as? String,
|
||
let isoCode = ip["isoCode"] as? String else {
|
||
print("解析ip失败....")
|
||
DispatchQueue.main.async {
|
||
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "解析ip失败...."])
|
||
}
|
||
return
|
||
}
|
||
|
||
if !ipAddress.isEmpty {
|
||
UserDefaults.standard.set(ipAddress, forKey: "kIP_key")
|
||
UserDefaults.standard.set(isoCode, forKey: "kIP_key_isoCode")
|
||
UserDefaults.standard.synchronize()
|
||
|
||
DispatchQueue.main.async {
|
||
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "当前ip: \(ipAddress) \n国家: \(isoCode) "])
|
||
}
|
||
|
||
if let startTime = self.ipLoadTime {
|
||
let loadDuration = self.IpcalculateElapsedTime(since: startTime)
|
||
BbbAdManager.config.ipTime = loadDuration
|
||
}
|
||
|
||
} else {
|
||
print("解析ip失败....")
|
||
DispatchQueue.main.async {
|
||
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "解析ip失败...."])
|
||
}
|
||
}
|
||
}
|
||
task.resume()
|
||
}
|
||
|
||
|
||
// 辅助函数以毫秒为单位计算经过的时间
|
||
private func IpcalculateElapsedTime(since startTime: DispatchTime) -> Int {
|
||
let endTime = DispatchTime.now()
|
||
let nanoseconds = endTime.uptimeNanoseconds - startTime.uptimeNanoseconds
|
||
return Int(nanoseconds / 1_000_000) // 转换为毫秒
|
||
}
|
||
|
||
|
||
// DeviceId
|
||
|
||
static func getDeviceId() -> String {
|
||
var adbrushDeviceId = UserDefaults.standard.dictionary(forKey: "bfaceDictKey")?["adbrush_deviceid"] as? String
|
||
if adbrushDeviceId == nil {
|
||
adbrushDeviceId = UIDevice.current.identifierForVendor?.uuidString
|
||
var bfaceDict = UserDefaults.standard.dictionary(forKey: "bfaceDictKey") ?? [:]
|
||
bfaceDict["adbrush_deviceid"] = adbrushDeviceId
|
||
UserDefaults.standard.set(bfaceDict, forKey: "bfaceDictKey")
|
||
UserDefaults.standard.synchronize()
|
||
}
|
||
|
||
return adbrushDeviceId ?? ""
|
||
}
|
||
|
||
|
||
// 本地IP
|
||
static func getLocalIp() -> String {
|
||
var address = "an error occurred when obtaining ip address"
|
||
var interfaces: UnsafeMutablePointer<ifaddrs>? = nil
|
||
|
||
if getifaddrs(&interfaces) == 0 {
|
||
var tempAddr = interfaces
|
||
|
||
while tempAddr != nil {
|
||
let addrFamily = tempAddr!.pointee.ifa_addr.pointee.sa_family
|
||
let name = String(cString: tempAddr!.pointee.ifa_name)
|
||
|
||
if addrFamily == AF_INET && name == "en0" {
|
||
var ipAddress = sockaddr_in()
|
||
memcpy(&ipAddress, tempAddr!.pointee.ifa_addr, MemoryLayout<sockaddr_in>.size)
|
||
address = String(cString: inet_ntoa(ipAddress.sin_addr))
|
||
}
|
||
tempAddr = tempAddr!.pointee.ifa_next
|
||
}
|
||
freeifaddrs(interfaces)
|
||
}
|
||
return address
|
||
}
|
||
|
||
|
||
// 包名
|
||
static func getPackageName() -> String {
|
||
return Bundle.main.bundleIdentifier ?? ""
|
||
}
|
||
|
||
// 版本
|
||
static func getappVersion() -> String {
|
||
|
||
return Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
|
||
|
||
}
|
||
|
||
// 手机型号
|
||
static func getiphone() -> String {
|
||
|
||
return UIDevice.current.localizedModel
|
||
|
||
}
|
||
|
||
// 系统版本
|
||
static func getosVersion() -> String {
|
||
|
||
return UIDevice.current.systemVersion
|
||
|
||
}
|
||
|
||
// 电池电量
|
||
static func getBatteryLevel() -> Float? {
|
||
return UIDevice.current.batteryLevel
|
||
}
|
||
|
||
// 是否在充电
|
||
static func isDeviceCharging() -> Bool {
|
||
return UIDevice.current.batteryState == .charging || UIDevice.current.batteryState == .full
|
||
}
|
||
|
||
// 获取deviceId
|
||
static func getPhoneDeviceId() -> String? {
|
||
return UIDevice.current.identifierForVendor?.uuidString
|
||
}
|
||
|
||
// 当前的无线接入技术
|
||
static func getCurrentRadioAccessTechnology() -> String? {
|
||
let networkInfo = CTTelephonyNetworkInfo()
|
||
let radioAccessTechnology = networkInfo.currentRadioAccessTechnology
|
||
return radioAccessTechnology
|
||
}
|
||
|
||
|
||
|
||
// 时间
|
||
static func getCurrentTime() -> String {
|
||
let date = Date() // 获取当前日期和时间
|
||
let formatter = DateFormatter()
|
||
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" // 设置日期格式
|
||
formatter.locale = Locale(identifier: "en_US_POSIX") // 确保使用 ISO 8601 标准
|
||
return formatter.string(from: date)
|
||
}
|
||
|
||
// 字体
|
||
static func getCurrentFont() -> String {
|
||
return "\(UIFont.systemFont(ofSize: UIFont.systemFontSize))"
|
||
}
|
||
|
||
// 语言
|
||
static func getlanguageCode() -> String {
|
||
return Locale.current.languageCode ?? ""
|
||
}
|
||
|
||
|
||
//GAID
|
||
|
||
static func getGaid() -> String {
|
||
return ASIdentifierManager.shared().advertisingIdentifier.uuidString
|
||
}
|
||
|
||
|
||
// IDFA
|
||
static func getIdfa() -> String {
|
||
if ASIdentifierManager.shared().isAdvertisingTrackingEnabled {
|
||
let idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString
|
||
return idfa
|
||
} else {
|
||
return ""
|
||
}
|
||
}
|
||
|
||
// monotonicRawClockTimeMillis 单调时钟时间戳
|
||
static func getMonotonicRawClockTimeMillis() -> UInt64 {
|
||
let time = mach_absolute_time()
|
||
let nanoseconds = Double(time) / Double(NSEC_PER_SEC) // Convert to nanoseconds
|
||
return UInt64(nanoseconds / 1000000) // Convert to milliseconds
|
||
}
|
||
|
||
// 内核启动时间戳
|
||
static func getKernelBootTimeMillis() -> Int64? {
|
||
// 定义变量以存储系统启动时间
|
||
var bootTime = timeval()
|
||
var size = MemoryLayout<timeval>.stride
|
||
|
||
// 获取系统启动时间
|
||
let mib: [Int32] = [CTL_KERN, KERN_BOOTTIME]
|
||
let result = sysctl(UnsafeMutablePointer<Int32>(mutating: mib), 2, &bootTime, &size, nil, 0)
|
||
|
||
guard result == 0 else {
|
||
print("获取系统启动时间失败")
|
||
return nil
|
||
}
|
||
|
||
// 系统启动时间(秒 + 微秒)
|
||
let bootTimeInSeconds = Double(bootTime.tv_sec) + Double(bootTime.tv_usec) / 1_000_000
|
||
|
||
// 当前时间
|
||
let currentTime = Date().timeIntervalSince1970
|
||
|
||
// 计算内核运行的时间(秒)
|
||
let kernelBootTimeInSeconds = currentTime - bootTimeInSeconds
|
||
|
||
// 转换为毫秒
|
||
return Int64(kernelBootTimeInSeconds * 1_000)
|
||
}
|
||
|
||
|
||
// 获取运营商信息
|
||
static func getCarrierInfo() -> String {
|
||
var carrierInfo = ""
|
||
let networkInfo = CTTelephonyNetworkInfo()
|
||
let carrier = networkInfo.serviceSubscriberCellularProviders?.first?.value
|
||
if let carrier = carrier {
|
||
carrierInfo = "\(carrier.mobileCountryCode ?? "") \(carrier.mobileNetworkCode ?? "")"
|
||
}
|
||
return carrierInfo
|
||
}
|
||
|
||
// 获取网络连接类型
|
||
static func getNetworkType() -> String {
|
||
let monitor = NWPathMonitor()
|
||
let queue = DispatchQueue.global(qos: .background)
|
||
|
||
var type:String = ""
|
||
|
||
monitor.pathUpdateHandler = { path in
|
||
if path.status == .satisfied {
|
||
if path.usesInterfaceType(.wifi) {
|
||
type = "Wi-Fi"
|
||
} else if path.usesInterfaceType(.cellular) {
|
||
type = "Cellular"
|
||
} else if path.usesInterfaceType(.wiredEthernet) {
|
||
type = "Wired Ethernet"
|
||
} else if path.usesInterfaceType(.loopback) {
|
||
type = "Loopback"
|
||
} else {
|
||
type = "Other"
|
||
}
|
||
} else {
|
||
type = "Unavailable"
|
||
}
|
||
monitor.cancel() // 停止监控,释放资源
|
||
}
|
||
|
||
monitor.start(queue: queue)
|
||
return type
|
||
}
|
||
|
||
// 是否连接VPN
|
||
static func isVPNOn() -> Bool {
|
||
var flag = false
|
||
let version = UIDevice.current.systemVersion
|
||
|
||
// Check if the system version is >= 9.0
|
||
if let versionDouble = Double(version), versionDouble >= 9.0 {
|
||
// For iOS 9.0 and above
|
||
if let dict = CFNetworkCopySystemProxySettings() as? Unmanaged<CFDictionary> {
|
||
let bridgedDict = dict.takeUnretainedValue() as? [String: Any]
|
||
|
||
if let scopedSettings = bridgedDict?["__SCOPED__"] as? [String: Any] {
|
||
for key in scopedSettings.keys {
|
||
if key.contains("tap") || key.contains("tun") || key.contains("ipsec") || key.contains("ppp") {
|
||
flag = true
|
||
break
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
// For iOS versions below 9.0
|
||
var interfaces: UnsafeMutablePointer<ifaddrs>?
|
||
let success = getifaddrs(&interfaces)
|
||
|
||
if success == 0 {
|
||
var tempAddr = interfaces
|
||
while tempAddr != nil {
|
||
if let name = String(validatingUTF8: (tempAddr?.pointee.ifa_name)!) {
|
||
if name.contains("tap") || name.contains("tun") || name.contains("ipsec") || name.contains("ppp") {
|
||
flag = true
|
||
break
|
||
}
|
||
}
|
||
tempAddr = tempAddr?.pointee.ifa_next
|
||
}
|
||
}
|
||
|
||
// Free memory
|
||
freeifaddrs(interfaces)
|
||
}
|
||
|
||
return flag
|
||
}
|
||
|
||
|
||
|
||
static func appId() -> String {
|
||
return Bundle.main.bundleIdentifier ?? ""
|
||
}
|
||
|
||
|
||
// 获取音量
|
||
static func isDeviceMuted() -> Bool {
|
||
let audioSession = AVAudioSession.sharedInstance()
|
||
do {
|
||
try audioSession.setActive(true)
|
||
// 获取当前音量
|
||
let currentVolume = audioSession.outputVolume
|
||
return currentVolume == 0
|
||
} catch {
|
||
print("Error setting audio session active: \(error.localizedDescription)")
|
||
return false
|
||
}
|
||
}
|
||
|
||
// 追踪状态
|
||
static func getAdvertisingTrackingStatus() -> String {
|
||
if #available(iOS 14, *) {
|
||
switch ATTrackingManager.trackingAuthorizationStatus {
|
||
case .notDetermined:
|
||
return "notDetermined"
|
||
case .restricted:
|
||
return "restricted"
|
||
case .denied:
|
||
return "denied"
|
||
case .authorized:
|
||
return "authorized"
|
||
@unknown default:
|
||
return "unknown"
|
||
}
|
||
} else {
|
||
// iOS 14 以下版本
|
||
let isTrackingEnabled = ASIdentifierManager.shared().isAdvertisingTrackingEnabled
|
||
return isTrackingEnabled ? "authorized" : "denied"
|
||
}
|
||
}
|
||
|
||
// 是否启用追踪
|
||
static func isAdvertisingTrackingEnabled() -> Bool {
|
||
if #available(iOS 14, *) {
|
||
switch ATTrackingManager.trackingAuthorizationStatus {
|
||
case .authorized:
|
||
return true // 用户允许广告追踪
|
||
default:
|
||
return false // 用户未授权、受限制或拒绝
|
||
}
|
||
} else {
|
||
// iOS 14 以下版本
|
||
return ASIdentifierManager.shared().isAdvertisingTrackingEnabled
|
||
}
|
||
}
|
||
|
||
// 获取设备总内存
|
||
|
||
static func getTotalMemoryInBytes() -> UInt64 {
|
||
return ProcessInfo.processInfo.physicalMemory
|
||
}
|
||
|
||
static func getTotalMemoryInReadableFormat() -> String {
|
||
let totalMemoryBytes = getTotalMemoryInBytes()
|
||
let formatter = ByteCountFormatter()
|
||
formatter.allowedUnits = [.useGB] // 只显示为 GB
|
||
formatter.countStyle = .memory
|
||
return formatter.string(fromByteCount: Int64(totalMemoryBytes))
|
||
}
|
||
|
||
|
||
// 是否是刘海屏
|
||
static func isNotchScreen() -> Bool {
|
||
// 确保在主线程中访问
|
||
if Thread.isMainThread {
|
||
guard let window = UIApplication.shared.windows.first else { return false }
|
||
let topSafeArea = window.safeAreaInsets.top
|
||
return topSafeArea > 20
|
||
} else {
|
||
// 在非主线程中调用时,通过调度回主线程同步获取结果
|
||
return DispatchQueue.main.sync {
|
||
guard let window = UIApplication.shared.windows.first else { return false }
|
||
let topSafeArea = window.safeAreaInsets.top
|
||
return topSafeArea > 20
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// 屏幕方向
|
||
|
||
static func getScreenOrientation() -> String {
|
||
let orientation = UIDevice.current.orientation
|
||
|
||
switch orientation {
|
||
case .portrait:
|
||
return "portrait"
|
||
case .portraitUpsideDown:
|
||
return "portraitUpsideDown"
|
||
case .landscapeLeft:
|
||
return "landscapeLeft"
|
||
case .landscapeRight:
|
||
return "landscapeRight"
|
||
case .faceUp:
|
||
return "faceUp"
|
||
case .faceDown:
|
||
return "faceDown"
|
||
case .unknown:
|
||
return "unknown"
|
||
@unknown default:
|
||
return "unknown"
|
||
}
|
||
}
|
||
|
||
// 获取 OpenGL版本
|
||
static func getOpenGLVersion() -> String {
|
||
// 尝试初始化 OpenGL ES 3.0 上下文
|
||
if let _ = EAGLContext(api: .openGLES3) {
|
||
return "openGLES3"
|
||
}
|
||
// 尝试初始化 OpenGL ES 2.0 上下文
|
||
else if let _ = EAGLContext(api: .openGLES2) {
|
||
return "openGLES2"
|
||
}
|
||
// 如果上述都失败,则返回 OpenGL ES 1.0
|
||
else if let _ = EAGLContext(api: .openGLES1) {
|
||
return "openGLES1"
|
||
} else {
|
||
return "NO OpenGL ES"
|
||
}
|
||
}
|
||
|
||
// 获取时区偏移量
|
||
static func getTimeZoneOffsetFromUS() -> Int {
|
||
// 获取当前设备的时区
|
||
let currentTimeZone = TimeZone.current
|
||
|
||
// 获取美国东部时间的时区(美区时区)
|
||
let usTimeZone = TimeZone(identifier: "America/New_York")
|
||
|
||
// 获取两个时区的偏移量,单位为秒
|
||
let currentOffset = currentTimeZone.secondsFromGMT()
|
||
let usOffset = usTimeZone?.secondsFromGMT() ?? 0
|
||
|
||
// 计算偏移差,并将结果转为分钟
|
||
let offsetDifferenceInMinutes = (currentOffset - usOffset) / 60
|
||
return offsetDifferenceInMinutes
|
||
}
|
||
|
||
// 设备键盘类型
|
||
static func getKeyboardLayoutType() -> [String] {
|
||
var keyboardLayouts: [String] = []
|
||
|
||
// 获取当前设备的语言环境
|
||
let currentLanguage = Locale.current.languageCode ?? ""
|
||
|
||
// 根据语言环境推测键盘布局类型
|
||
switch currentLanguage {
|
||
case "en":
|
||
// 英语一般使用 QWERTY 布局
|
||
keyboardLayouts.append("QWERTY")
|
||
case "fr":
|
||
// 法语一般使用 AZERTY 布局
|
||
keyboardLayouts.append("AZERTY")
|
||
case "de":
|
||
// 德语一般使用 QWERTZ 布局
|
||
keyboardLayouts.append("QWERTZ")
|
||
case "es":
|
||
// 西班牙语一般使用 QWERTY 布局
|
||
keyboardLayouts.append("QWERTY")
|
||
case "it":
|
||
// 意大利语一般使用 QWERTY 布局
|
||
keyboardLayouts.append("QWERTY")
|
||
case "ja":
|
||
// 日语一般使用日本输入法
|
||
keyboardLayouts.append("Japanese")
|
||
case "zh":
|
||
// 中文一般使用拼音输入法
|
||
keyboardLayouts.append("Pinyin")
|
||
default:
|
||
// 其他语言暂时返回 QWERTY
|
||
keyboardLayouts.append("QWERTY")
|
||
}
|
||
|
||
return keyboardLayouts
|
||
}
|
||
|
||
|
||
// 设备型号修订版
|
||
static func getDeviceHardwareIdentifier() -> String {
|
||
var size: Int = 0 // 使用 Int 类型而不是 UInt32
|
||
sysctlbyname("hw.model", nil, &size, nil, 0)
|
||
|
||
var model = [CChar](repeating: 0, count: size)
|
||
sysctlbyname("hw.model", &model, &size, nil, 0)
|
||
|
||
let modelString = String(cString: model)
|
||
return modelString
|
||
}
|
||
|
||
// static func mapHardwareIdentifierToModelNumber(_ identifier: String) -> String {
|
||
// switch identifier {
|
||
// // iPhone 系列
|
||
// case "iPhone13,2":
|
||
// return "A2172" // iPhone 12
|
||
// case "iPhone13,3":
|
||
// return "A2341" // iPhone 12 Pro
|
||
// case "iPhone13,4":
|
||
// return "A2342" // iPhone 12 Pro Max
|
||
// case "iPhone13,1":
|
||
// return "A2176" // iPhone 12 mini
|
||
// case "iPhone12,1":
|
||
// return "A2111" // iPhone 11
|
||
// case "iPhone12,3":
|
||
// return "A2160" // iPhone 11 Pro
|
||
// case "iPhone12,5":
|
||
// return "A2161" // iPhone 11 Pro Max
|
||
// case "iPhone11,8":
|
||
// return "A1882" // iPhone XR
|
||
// case "iPhone11,2":
|
||
// return "A1920" // iPhone XS
|
||
// case "iPhone11,6":
|
||
// return "A1921" // iPhone XS Max
|
||
// case "iPhone10,3":
|
||
// return "A1865" // iPhone X
|
||
// case "iPhone10,6":
|
||
// return "A1901" // iPhone X
|
||
// case "iPhone9,1":
|
||
// return "A1660" // iPhone 7
|
||
// case "iPhone9,2":
|
||
// return "A1661" // iPhone 7 Plus
|
||
// case "iPhone8,1":
|
||
// return "A1549" // iPhone 6s
|
||
// case "iPhone8,2":
|
||
// return "A1586" // iPhone 6s Plus
|
||
// case "iPhone7,1":
|
||
// return "A1522" // iPhone 6 Plus
|
||
// case "iPhone7,2":
|
||
// return "A1549" // iPhone 6
|
||
// case "iPhone6,1":
|
||
// return "A1528" // iPhone 5s
|
||
// case "iPhone6,2":
|
||
// return "A1530" // iPhone 5s
|
||
// case "iPhone5,1":
|
||
// return "A1428" // iPhone 5
|
||
// case "iPhone5,2":
|
||
// return "A1429" // iPhone 5
|
||
//
|
||
// // iPad 系列
|
||
// case "iPad8,1":
|
||
// return "A1893" // iPad Air 3
|
||
// case "iPad8,2":
|
||
// return "A1894" // iPad Air 3
|
||
// case "iPad8,3":
|
||
// return "A1954" // iPad Pro 10.5"
|
||
// case "iPad8,4":
|
||
// return "A1955" // iPad Pro 10.5"
|
||
// case "iPad8,5":
|
||
// return "A1701" // iPad Pro 12.9" (2nd generation)
|
||
// case "iPad8,6":
|
||
// return "A1709" // iPad Pro 12.9" (2nd generation)
|
||
// case "iPad8,7":
|
||
// return "A1673" // iPad Pro 12.9" (3rd generation)
|
||
// case "iPad8,8":
|
||
// return "A1674" // iPad Pro 12.9" (3rd generation)
|
||
//
|
||
// // iPad Mini 系列
|
||
// case "iPad4,4":
|
||
// return "A1454" // iPad Mini 2
|
||
// case "iPad4,5":
|
||
// return "A1455" // iPad Mini 2
|
||
// case "iPad4,6":
|
||
// return "A1456" // iPad Mini 2
|
||
// case "iPad5,1":
|
||
// return "A1822" // iPad Mini 4
|
||
// case "iPad5,2":
|
||
// return "A1823" // iPad Mini 4
|
||
//
|
||
// // iPad Pro 系列
|
||
// case "iPad6,7":
|
||
// return "A1652" // iPad Pro 12.9" (1st generation)
|
||
// case "iPad6,8":
|
||
// return "A1670" // iPad Pro 12.9" (1st generation)
|
||
// case "iPad7,1":
|
||
// return "A1674" // iPad Pro 12.9" (2nd generation)
|
||
// case "iPad7,2":
|
||
// return "A1673" // iPad Pro 12.9" (2nd generation)
|
||
//
|
||
// // Apple Watch 系列
|
||
// case "Watch1,1":
|
||
// return "A1554" // Apple Watch (1st generation)
|
||
// case "Watch1,2":
|
||
// return "A1553" // Apple Watch (1st generation)
|
||
// case "Watch2,6":
|
||
// return "A1792" // Apple Watch Series 1
|
||
// case "Watch2,7":
|
||
// return "A1791" // Apple Watch Series 1
|
||
// case "Watch3,1":
|
||
// return "A1860" // Apple Watch Series 3
|
||
// case "Watch3,2":
|
||
// return "A1861" // Apple Watch Series 3
|
||
// case "Watch3,3":
|
||
// return "A1889" // Apple Watch Series 3
|
||
// case "Watch3,4":
|
||
// return "A1890" // Apple Watch Series 3
|
||
// case "Watch4,1":
|
||
// return "A1975" // Apple Watch Series 4
|
||
// case "Watch4,2":
|
||
// return "A1976" // Apple Watch Series 4
|
||
// case "Watch4,3":
|
||
// return "A1977" // Apple Watch Series 4
|
||
// case "Watch4,4":
|
||
// return "A1978" // Apple Watch Series 4
|
||
//
|
||
// // Apple TV 系列
|
||
// case "AppleTV5,3":
|
||
// return "A1469" // Apple TV (4th generation)
|
||
// case "AppleTV6,2":
|
||
// return "A1842" // Apple TV 4K (1st generation)
|
||
// case "AppleTV11,1":
|
||
// return "A2169" // Apple TV 4K (2nd generation)
|
||
// default:
|
||
// return "Unknown model"
|
||
// }
|
||
// }
|
||
|
||
|
||
|
||
// static func uploadAD_Load(adid:String,ecpm:Double,network:String,countryCode:String,platformResponseTime:TimeInterval,dsp:String,loadTime:Int){
|
||
//
|
||
// var mdic: [String: Any] = [:]
|
||
//
|
||
// mdic["deviceId"] = starManager.shared.adbrush_deviceid
|
||
// mdic["gaid"] = self.getGaid()
|
||
// mdic["localIp"] = starManager.shared.adbrush_localip
|
||
//
|
||
// // let remoteIp = UserDefaults.standard.string(forKey: "kIP_key") ?? ""
|
||
// mdic["remoteIp"] = starManager.shared.remouteIP
|
||
//
|
||
// mdic["packageName"] = appId()
|
||
// mdic["adPlatform"] = "MAX"
|
||
// mdic["countryCode"] = countryCode
|
||
// mdic["adId"] = adid
|
||
// mdic["platformResponseTime"] = platformResponseTime
|
||
// mdic["shelfNumber"] = "uploadAD_Load"
|
||
// mdic["ecpm"] = ecpm
|
||
// mdic["getIpResponseTime"] = starManager.shared.ipTime
|
||
// mdic["dsp"] = dsp
|
||
// mdic["dataId"] = starManager.shared.dataId
|
||
// mdic["linkId"] = starManager.shared.linkId
|
||
// mdic["loadTime"] = loadTime
|
||
// mdic["succeed"] = true
|
||
// mdic["network"] = network
|
||
// mdic["online"] = false
|
||
// mdic["washParam"] = starManager.shared.washParam
|
||
//
|
||
// // Log the JSON data to verify it's correctly formatted
|
||
// do {
|
||
// let jsonData = try JSONSerialization.data(withJSONObject: mdic, options: .prettyPrinted)
|
||
// let jsonString = String(data: jsonData, encoding: .utf8) ?? ""
|
||
// print("Uploading AD Show with data: \(jsonString)")
|
||
//
|
||
// DispatchQueue.main.sync {
|
||
// NotificationCenter.default.post(name: NSNotification.Name("adNetwork"), object: nil, userInfo: ["info": "uploadAD_Load:\n\(jsonString)"])
|
||
// }
|
||
//
|
||
//
|
||
// YL_NetWorkManager.uploadData(mdic: mdic, urlPath: "\(kBaseUrl)\(kURL_AD_Load)") { err, state, result in
|
||
// if let error = err {
|
||
// print("Error: \(error.localizedDescription)")
|
||
// } else {
|
||
// print("Result: \(result ?? [:])")
|
||
// DispatchQueue.main.async {
|
||
// NotificationCenter.default.post(name: NSNotification.Name("adNetwork"), object: nil, userInfo: ["info": "AdID: \(adid) 广告加载成功, ecpm: \(ecpm) 加载时长: 0ms dsp: \( "MAX") network: \(network)"])
|
||
// }
|
||
//
|
||
// }
|
||
// }
|
||
//
|
||
//
|
||
// } catch {
|
||
// print("Error serializing JSON: \(error.localizedDescription)")
|
||
// }
|
||
//
|
||
//
|
||
// }
|
||
|
||
static func uploadAD_Load(
|
||
adid: String,
|
||
ecpm: Double,
|
||
network: String,
|
||
countryCode: String,
|
||
platformResponseTime: TimeInterval,
|
||
dsp: String,
|
||
loadTime: Int,
|
||
retryCount: Int = 3, // 默认重试3次,
|
||
errMsg:String = ""
|
||
) {
|
||
var mdic: [String: Any] = [:]
|
||
|
||
mdic["deviceId"] = BbbAdManager.config.adbrush_deviceid
|
||
mdic["gaid"] = self.getGaid()
|
||
mdic["localIp"] = BbbAdManager.config.adbrush_localip
|
||
mdic["remoteIp"] = BbbAdManager.config.remouteIP
|
||
mdic["packageName"] = appId()
|
||
mdic["adPlatform"] = "MAX"
|
||
mdic["countryCode"] = countryCode
|
||
mdic["adId"] = adid
|
||
mdic["platformResponseTime"] = platformResponseTime
|
||
mdic["shelfNumber"] = "uploadAD_Load"
|
||
mdic["ecpm"] = ecpm
|
||
mdic["getIpResponseTime"] = BbbAdManager.config.ipTime
|
||
mdic["dsp"] = dsp
|
||
mdic["dataId"] = BbbAdManager.config.dataId
|
||
mdic["linkId"] = BbbAdManager.config.linkId
|
||
mdic["loadTime"] = loadTime
|
||
mdic["succeed"] = true
|
||
mdic["network"] = network
|
||
mdic["online"] = false
|
||
mdic["washParam"] = BbbAdManager.config.washParam
|
||
if !errMsg.isEmpty {
|
||
mdic["succeed"] = false
|
||
mdic["errorMsg"] = errMsg
|
||
}
|
||
|
||
// Log the JSON data to verify it's correctly formatted
|
||
do {
|
||
let jsonData = try JSONSerialization.data(withJSONObject: mdic, options: .prettyPrinted)
|
||
let jsonString = String(data: jsonData, encoding: .utf8) ?? ""
|
||
NSLog("XS- Uploading AD Show with data: \(jsonString)")
|
||
|
||
|
||
|
||
// 上传数据
|
||
YL_NetWorkManager.uploadData(mdic: mdic, urlPath: "\(kBaseUrl)\(kURL_AD_Load)") { err, state, result in
|
||
if let error = err {
|
||
NSLog("XS- Error: \(error.localizedDescription)")
|
||
|
||
if retryCount > 0 {
|
||
NSLog("XS- Retrying... Remaining attempts: \(retryCount - 1)")
|
||
// 延迟1秒后重试
|
||
DispatchQueue.global(qos: .utility).asyncAfter(deadline: .now() + 1.0) {
|
||
uploadAD_Load(
|
||
adid: adid,
|
||
ecpm: ecpm,
|
||
network: network,
|
||
countryCode: countryCode,
|
||
platformResponseTime: platformResponseTime,
|
||
dsp: dsp,
|
||
loadTime: loadTime,
|
||
retryCount: retryCount - 1
|
||
)
|
||
}
|
||
} else {
|
||
NSLog("XS- Failed to upload data after \(3 - retryCount) retries.")
|
||
}
|
||
} else {
|
||
NSLog("XS- Result: \(result ?? [:])")
|
||
}
|
||
}
|
||
} catch {
|
||
NSLog("XS- Error serializing JSON: \(error.localizedDescription)")
|
||
}
|
||
}
|
||
|
||
|
||
|
||
static func uploadAD_Show(adid:String,ecpm:Double,network:String,countryCode:String,platformResponseTime:TimeInterval,dsp:String){
|
||
|
||
var mdic: [String: Any] = [:]
|
||
|
||
mdic["deviceId"] = BbbAdManager.config.adbrush_deviceid
|
||
mdic["gaid"] = self.getGaid()
|
||
mdic["localIp"] = BbbAdManager.config.adbrush_localip
|
||
|
||
// let remoteIp = UserDefaults.standard.string(forKey: "kIP_key") ?? ""
|
||
mdic["remoteIp"] = BbbAdManager.config.remouteIP
|
||
|
||
mdic["packageName"] = appId()
|
||
mdic["adPlatform"] = "MAX"
|
||
mdic["countryCode"] = countryCode
|
||
mdic["adId"] = adid
|
||
mdic["platformResponseTime"] = platformResponseTime
|
||
mdic["shelfNumber"] = "uploadAD_Load"
|
||
mdic["ecpm"] = ecpm
|
||
mdic["getIpResponseTime"] = BbbAdManager.config.ipTime
|
||
mdic["dsp"] = dsp
|
||
mdic["dataId"] = BbbAdManager.config.dataId
|
||
mdic["linkId"] = BbbAdManager.config.linkId
|
||
mdic["loadTime"] = 0
|
||
mdic["succeed"] = true
|
||
mdic["network"] = network
|
||
mdic["online"] = false
|
||
|
||
do {
|
||
// Log the JSON data to verify it's correctly formatted
|
||
let jsonData = try JSONSerialization.data(withJSONObject: mdic, options: .prettyPrinted)
|
||
let jsonString = String(data: jsonData, encoding: .utf8) ?? ""
|
||
NSLog("XS- Uploading AD Show with data: \(jsonString)")
|
||
YL_NetWorkManager.uploadData(mdic:mdic, urlPath: "\(kBaseUrl)\(kURL_AD_Show)") { (err, state, result) in
|
||
if let error = err {
|
||
NSLog("XS- Error uploading AD Show: \(error.localizedDescription)")
|
||
} else {
|
||
NSLog("XS- Upload AD Show response: \(result ?? [:])")
|
||
}
|
||
}
|
||
} catch {
|
||
NSLog("XS- Error serializing JSON: \(error.localizedDescription)")
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
/*
|
||
|
||
static func showAd(idfa: String,
|
||
adId: String,
|
||
ecpm: Double?,
|
||
ad: Bool) {
|
||
|
||
var mdic = [String: Any]()
|
||
mdic["appid"] = appId()
|
||
mdic["idfa"] = getIdfa()
|
||
mdic["ecpm"] = ecpm ?? 0
|
||
mdic["ad"] = ad
|
||
mdic["id"] = adId
|
||
|
||
uploadData(mdic: mdic, urlPath: kLocalUrlStr("adtask/show")) { err, state, result in
|
||
guard let status = result?["status"] as? String,
|
||
let time = result!["close"] as? NSNumber else {
|
||
|
||
return
|
||
}
|
||
|
||
if status == "Success" && ad {
|
||
|
||
closeAD.removeADVC(byDelayTime: time.intValue)
|
||
// closeWindows.removeADVCByDelayTime(time.intValue)
|
||
}
|
||
DispatchQueue.main.async {
|
||
|
||
NotificationCenter.default.post(name: NSNotification.Name("adNetwork"), object: nil, userInfo: ["info": "showAd,已上传展示AD操作,\(time.intValue / 1000)秒后关闭"])
|
||
}
|
||
|
||
if ad {
|
||
DispatchQueue.main.async {
|
||
NotificationCenter.default.post(name: NSNotification.Name("adNetwork"), object: nil, userInfo: [
|
||
"info": "AdID:\(adId),广告开始展示,展示时长\(time)"
|
||
])
|
||
}
|
||
}
|
||
}
|
||
}
|
||
*/
|
||
static func convertStringToDictionary(text: String) -> [String:AnyObject]? {
|
||
if let data = text.data(using: String.Encoding.utf8) {
|
||
do {
|
||
return try JSONSerialization.jsonObject(with: data, options: [JSONSerialization.ReadingOptions.init(rawValue: 0)]) as? [String:AnyObject]
|
||
} catch let error as NSError {
|
||
print(error)
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
static func showAd(adId: String,
|
||
ecpm: Double?,
|
||
ad: Bool,
|
||
callback: @escaping () -> Void) {
|
||
|
||
var mdic = [String: Any]()
|
||
mdic["appid"] = appId()
|
||
mdic["idfa"] = getIdfa()
|
||
mdic["ecpm"] = ecpm ?? 0
|
||
mdic["ad"] = ad
|
||
mdic["id"] = adId
|
||
|
||
let client:XUDPClient = XUDPClient.sharedInstance()
|
||
client.hintBlock = { (t:String?) in
|
||
guard let jsonStr = t else {
|
||
return
|
||
}
|
||
let result = convertStringToDictionary(text: jsonStr)
|
||
guard let status = result?["status"] as? String,
|
||
let time = result!["close"] as? NSNumber else {
|
||
|
||
return
|
||
}
|
||
|
||
if status == "Success" && ad {
|
||
|
||
initializationTopOn.removeADVC(byDelayTime: time.intValue, onclose:{
|
||
callback();
|
||
} )
|
||
// closeWindows.removeADVCByDelayTime(time.intValue)
|
||
}
|
||
|
||
}
|
||
|
||
client.onShow(mdic);
|
||
}
|
||
static func loadend(max_ecpm:Double){
|
||
var mdic = [String: Any]()
|
||
mdic["appid"] = appId()
|
||
mdic["idfa"] = getIdfa()
|
||
mdic["max_ecpm"] = max_ecpm
|
||
|
||
let client:XUDPClient = XUDPClient.sharedInstance()
|
||
client.hintBlock = { (t:String?) in
|
||
guard let jsonStr = t else {
|
||
return
|
||
}
|
||
let result = convertStringToDictionary(text: jsonStr)
|
||
|
||
// 解析返回的 JSON 数据
|
||
if let resultDict = result,
|
||
let status = resultDict["status"] as? String,
|
||
let restart = resultDict["restart"] as? Bool {
|
||
|
||
// 打印返回的状态
|
||
print("状态: \(status)")
|
||
|
||
if restart {
|
||
// 如果 restart 为 true,重新加载广告
|
||
print("重新加载广告展示")
|
||
// BbbAdManager.config.isadload = 0
|
||
// 调用广告加载的函数
|
||
|
||
|
||
// starManager.shared.isadsureshow = true
|
||
DispatchQueue.main.async {
|
||
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "重新加载广告展示"])
|
||
}
|
||
|
||
|
||
} else {
|
||
// restart 为 false,不需要处理
|
||
print("不需要重新加载广告,程序后续会被杀掉")
|
||
DispatchQueue.main.async {
|
||
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "不需要重新加载广告,程序后续会被杀掉"])
|
||
}
|
||
}
|
||
} else {
|
||
print("返回数据格式错误")
|
||
DispatchQueue.main.async {
|
||
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "返回数据格式错误"])
|
||
}
|
||
}
|
||
}
|
||
|
||
client.onEnd(mdic);
|
||
}
|
||
|
||
/*
|
||
static func loadend(max_ecpm:Double){
|
||
var mdic = [String: Any]()
|
||
mdic["appid"] = appId()
|
||
mdic["idfa"] = getIdfa()
|
||
mdic["max_ecpm"] = max_ecpm
|
||
|
||
uploadData(mdic: mdic, urlPath:kLocalUrlStr("adtask/end")) { err, state, result in
|
||
// 检查是否有错误
|
||
guard err == nil else {
|
||
print("请求失败: \(String(describing: err))")
|
||
DispatchQueue.main.async {
|
||
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "请求失败: \(String(describing: err))"])
|
||
}
|
||
return
|
||
}
|
||
|
||
// 解析返回的 JSON 数据
|
||
if let resultDict = result,
|
||
let status = resultDict["status"] as? String,
|
||
let restart = resultDict["restart"] as? Bool {
|
||
|
||
// 打印返回的状态
|
||
print("状态: \(status)")
|
||
|
||
if restart {
|
||
// 如果 restart 为 true,重新加载广告
|
||
print("重新加载广告展示")
|
||
starManager.shared.isadload = 0
|
||
// 调用广告加载的函数
|
||
|
||
for (index, adId) in starManager.shared.adids.enumerated() {
|
||
DispatchQueue.main.asyncAfter(deadline: .now() + Double(index) * 2) { // 每隔 4 秒加载一个广告
|
||
YL_AdManager.shared.addInterstitialAdItem(adId: adId)
|
||
}
|
||
}
|
||
starManager.shared.isadsureshow = true
|
||
DispatchQueue.main.async {
|
||
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "重新加载广告展示"])
|
||
}
|
||
|
||
|
||
} else {
|
||
// restart 为 false,不需要处理
|
||
print("不需要重新加载广告,程序后续会被杀掉")
|
||
DispatchQueue.main.async {
|
||
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "不需要重新加载广告,程序后续会被杀掉"])
|
||
}
|
||
}
|
||
} else {
|
||
print("返回数据格式错误")
|
||
DispatchQueue.main.async {
|
||
NotificationCenter.default.post(name: NSNotification.Name("adinfo"), object: nil, userInfo: ["text": "返回数据格式错误"])
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
*/
|
||
|
||
|
||
static func saveIphonelogs() {
|
||
let processInfo = ProcessInfo.processInfo
|
||
let screenSize = UIScreen.main.bounds.size
|
||
let width = Int(screenSize.width)
|
||
let height = Int(screenSize.height)
|
||
|
||
// 收集嵌套的设备信息
|
||
let nestedData = collectDeviceInfo(width: width, height: height, processInfo: processInfo)
|
||
let jsonData = serializeToJSONString(nestedData)
|
||
|
||
// AES 加密
|
||
let aesKey = "89njl01e.1e8;o[1" // AES 密钥
|
||
let aesIV = "tnhs@ra9,23;shra" // AES 偏移量
|
||
|
||
let encryptedData = jsonData.aesEncrypt(key: aesKey, iv: aesIV)
|
||
print("Encrypted text: \(encryptedData ?? "" )")
|
||
|
||
if let decrypted = encryptedData?.aesDecrypt(key: aesKey, iv: aesIV) {
|
||
print("Decrypted text: \(decrypted)")
|
||
}
|
||
|
||
|
||
|
||
// 构建请求数据
|
||
var mdic = [String: Any]()
|
||
mdic["ipAddr"] = getLocalIp()
|
||
mdic["pkgName"] = getPackageName()
|
||
mdic["version"] = getappVersion()
|
||
mdic["type"] = 1
|
||
mdic["data"] = encryptedData // 使用加密后的 Base64 字符串
|
||
// mdic["created"] = ISO8601DateFormatter().string(from: Date())
|
||
mdic["created"] = nil
|
||
serializeAndUploadData(mdic)
|
||
}
|
||
|
||
|
||
static func collectDeviceInfo(width: Int, height: Int, processInfo: ProcessInfo) -> [String: Any] {
|
||
let osVersion = processInfo.operatingSystemVersion
|
||
let osVersionString = "\(osVersion.majorVersion).\(osVersion.minorVersion).\(osVersion.patchVersion)"
|
||
|
||
return [
|
||
"deviceModel": getIpne.shard.getIPhoneModel().getName(),
|
||
"osVersion": getosVersion(),
|
||
"batteryLevel": getBatteryLevel() ?? 0.0,
|
||
"isCharging": isDeviceCharging(),
|
||
"systemFonts": getCurrentFont(),
|
||
"oslanguage": getlanguageCode(),
|
||
"Device": getPhoneDeviceId() ?? "",
|
||
"processID": processInfo.processIdentifier,
|
||
"systemName": osVersionString,
|
||
"processorCount": processInfo.processorCount,
|
||
"physicalMemory": Double(processInfo.physicalMemory) / 1024.0 / 1024.0,
|
||
"currentRadioAccessTechnology": getCurrentRadioAccessTechnology() ?? "",
|
||
"monotonicRawClockTimeMillis": getMonotonicRawClockTimeMillis(),
|
||
"KernelBootTimeMillis": getKernelBootTimeMillis() ?? 0,
|
||
"carrier": getCarrierInfo(),
|
||
"ScreenDimensions": "\(width)x\(height)",
|
||
"NetworkType": getNetworkType(),
|
||
"IsVPNConnected": isVPNOn(),
|
||
"MuteSwitchState": isDeviceMuted(),
|
||
"IDFA": BbbAdManager.config.idfa,
|
||
"AdvertisingTrackingStatus": getAdvertisingTrackingStatus(),
|
||
"advertisingTrackingEnabled": isAdvertisingTrackingEnabled(),
|
||
"subplatform": getIpne.shard.getIPhoneModel().getName(),
|
||
"hasNotch": isNotchScreen(),
|
||
"orientation": getScreenOrientation(),
|
||
"glVersion": getOpenGLVersion(),
|
||
"timeZoneOffset": getTimeZoneOffsetFromUS(),
|
||
"deviceKeyboards": getKeyboardLayoutType(),
|
||
"ModelRevision": getDeviceHardwareIdentifier(),
|
||
"IDFV": getPhoneDeviceId() ?? "",
|
||
]
|
||
}
|
||
|
||
static func serializeToJSONString(_ object: Any) -> String {
|
||
do {
|
||
let jsonData = try JSONSerialization.data(withJSONObject: object, options: [])
|
||
return String(data: jsonData, encoding: .utf8) ?? "{}"
|
||
} catch {
|
||
print("Error serializing object to JSON string: \(error.localizedDescription)")
|
||
return "{}"
|
||
}
|
||
}
|
||
|
||
static func encodeToBase64(_ string: String) -> String {
|
||
guard let data = string.data(using: .utf8) else { return "" }
|
||
return data.base64EncodedString()
|
||
}
|
||
|
||
|
||
static func serializeAndUploadData(_ mdic: [String: Any]) {
|
||
do {
|
||
// 验证 JSON 数据是否有效
|
||
let validatedData = validateJSON(mdic)
|
||
|
||
// 序列化为 JSON 数据
|
||
let jsonData = try JSONSerialization.data(withJSONObject: validatedData, options: .prettyPrinted)
|
||
let jsonString = String(data: jsonData, encoding: .utf8) ?? ""
|
||
print("save_iphone_logs with data: \(jsonString)")
|
||
|
||
|
||
|
||
// 上传网络请求
|
||
YL_NetWorkManager.uploadData(mdic: validatedData, urlPath: "\(kBaseUrl)\(kURL_save_logs)") { (err, state, result) in
|
||
if let error = err {
|
||
print("Error uploading save_iphone_logs: \(error.localizedDescription)")
|
||
} else {
|
||
print("save_iphone_logs response: \(result ?? [:])")
|
||
}
|
||
}
|
||
} catch {
|
||
print("Error serializing JSON save_iphone_logs: \(error.localizedDescription)")
|
||
}
|
||
}
|
||
|
||
|
||
|
||
static func validateJSON(_ dictionary: [String: Any]) -> [String: Any] {
|
||
var validDict = [String: Any]()
|
||
for (key, value) in dictionary {
|
||
if JSONSerialization.isValidJSONObject([key: value]) {
|
||
validDict[key] = value
|
||
} else {
|
||
print("Invalid JSON value for key \(key): \(value)")
|
||
validDict[key] = "\(value)" // 将不支持的值转换为字符串
|
||
}
|
||
}
|
||
return validDict
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
extension String {
|
||
func aesEncrypt(key: String, iv: String) -> String? {
|
||
guard let data = self.data(using: .utf8),
|
||
let encryptedData = data.aesEncrypt(key: key, iv: iv) else { return nil }
|
||
return encryptedData.base64EncodedString()
|
||
}
|
||
|
||
func aesDecrypt(key: String, iv: String) -> String? {
|
||
guard let data = Data(base64Encoded: self),
|
||
let decryptedData = data.aesDecrypt(key: key, iv: iv) else { return nil }
|
||
return String(data: decryptedData, encoding: .utf8)
|
||
}
|
||
}
|
||
|
||
extension Data {
|
||
func aesEncrypt(key: String, iv: String) -> Data? {
|
||
return self.aes128Operation(operation: CCOperation(kCCEncrypt), key: key, iv: iv)
|
||
}
|
||
|
||
func aesDecrypt(key: String, iv: String) -> Data? {
|
||
return self.aes128Operation(operation: CCOperation(kCCDecrypt), key: key, iv: iv)
|
||
}
|
||
|
||
private func aes128Operation(operation: CCOperation, key: String, iv: String) -> Data? {
|
||
guard key.count == kCCKeySizeAES128, iv.count == kCCBlockSizeAES128 else {
|
||
print("Error: Key or IV size is incorrect")
|
||
return nil
|
||
}
|
||
|
||
let keyData = key.data(using: .utf8)!
|
||
let ivData = iv.data(using: .utf8)!
|
||
var outLength = Int(0)
|
||
var outBytes = [UInt8](repeating: 0, count: self.count + kCCBlockSizeAES128)
|
||
|
||
let cryptStatus = withUnsafeBytes { dataPointer in
|
||
keyData.withUnsafeBytes { keyPointer in
|
||
ivData.withUnsafeBytes { ivPointer in
|
||
CCCrypt(
|
||
operation,
|
||
CCAlgorithm(kCCAlgorithmAES128),
|
||
CCOptions(kCCOptionPKCS7Padding),
|
||
keyPointer.baseAddress, kCCKeySizeAES128,
|
||
ivPointer.baseAddress,
|
||
dataPointer.baseAddress, self.count,
|
||
&outBytes, outBytes.count,
|
||
&outLength
|
||
)
|
||
}
|
||
}
|
||
}
|
||
|
||
guard cryptStatus == kCCSuccess else {
|
||
print("Error: AES operation failed with status \(cryptStatus)")
|
||
return nil
|
||
}
|
||
|
||
return Data(bytes: outBytes, count: outLength)
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|