255 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Swift
		
	
	
		
		
			
		
	
	
			255 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Swift
		
	
	
|  | // | |||
|  | //  ViewController.swift | |||
|  | //  FusionAds | |||
|  | // | |||
|  | //  Created by Haoyi on 02/28/2025. | |||
|  | //  Copyright (c) 2025 Haoyi. All rights reserved. | |||
|  | // | |||
|  | 
 | |||
|  | import UIKit | |||
|  | import FusionAds | |||
|  | 
 | |||
|  | class ViewController: UIViewController { | |||
|  | 
 | |||
|  |     override func viewDidLoad() { | |||
|  |         super.viewDidLoad() | |||
|  |          | |||
|  |         Logger.setLogLevel(Logger.LogLevel.verbose) | |||
|  |          | |||
|  |         FusionAdsSdk.registerExternalAdPlatformSdkMapping(platform: AdPlatform.test, initializer: HappyPathAdsSdk.obtain) | |||
|  |          | |||
|  | //        testEngine() | |||
|  | //        testMaxEngine() | |||
|  | //        testIronSourceEngine() | |||
|  | //        testAdMobEngine() | |||
|  |         testMaxOfWithSameValue() | |||
|  |         do { | |||
|  |             try testAdsProfileJson() | |||
|  |             try testAdEngineConfigJson() | |||
|  |             testLogging() | |||
|  |         } catch {} | |||
|  |     } | |||
|  |      | |||
|  |     func testAdEngineConfigJson() throws { | |||
|  |         let config = AdEngineConfig(strategy: 0, faUnitId: "default", config: [ | |||
|  |             "test_key": "test_value", | |||
|  |             "test_int_key": 1, | |||
|  |             "test_bool_key": false, | |||
|  |             "test_nested_array": ["1", "2", "3"], | |||
|  |             "test_nested_dict": ["test":"value"] | |||
|  |         ]) | |||
|  |          | |||
|  |         let json = try! jsonEncode(config) | |||
|  |         let configOut = try! jsonDecode(AdEngineConfig.self, from: json) | |||
|  |         print(json) | |||
|  |         print(configOut) | |||
|  |     } | |||
|  |      | |||
|  |     private func jsonEncode(_ value: any Codable) throws -> String { | |||
|  |         let encoder = JSONEncoder() | |||
|  |         let data = try! encoder.encode(value) | |||
|  |         return String.init(data: data, encoding: .utf8)! | |||
|  |     } | |||
|  |      | |||
|  |     private func jsonDecode<T>(_ type: T.Type, from json: String) throws -> T where T : Decodable { | |||
|  |         let jsonDecoder = JSONDecoder() | |||
|  |         return try! jsonDecoder.decode(type, from: json.data(using: .utf8)!) | |||
|  |     } | |||
|  |      | |||
|  |     func testAdsProfileJson() throws { | |||
|  | 
 | |||
|  |         let jsonEncoder = JSONEncoder() | |||
|  |         let adsProfile = AdsProfile(adPlatforms: [AdPlatform.test], maxSdkKey: "") | |||
|  |         let data = try! jsonEncoder.encode(adsProfile) | |||
|  |         print(String.init(data: data, encoding: .utf8)!) | |||
|  |          | |||
|  |         let jsonData = #"{"ad_platforms":["TEST"],"max_sdk_key":"","amazon_app_id":null,"pubmatic_store_url":null,"uid2_token":null,"user_id":"","tp_creative_key":"","debug_mode":false,"segments":{"segments":[]}}"#.data(using: .utf8)! | |||
|  |         let jsonDecoder = JSONDecoder() | |||
|  |         let adsProfileFromJson = try! jsonDecoder.decode(AdsProfile.self, from: jsonData) | |||
|  |         print(adsProfileFromJson) | |||
|  |         print(adsProfile) | |||
|  |     } | |||
|  |      | |||
|  |     @MainActor func testEngine() { | |||
|  |         Task { | |||
|  |             let sdk = FusionAdsSdk(controller: self) | |||
|  |             let result = await sdk.initialize(adsProfile: AdsProfile(adPlatforms:[AdPlatform.max], maxSdkKey: "max_sdk_key")) | |||
|  |             assert(result, "sdk initialized success!") | |||
|  |              | |||
|  |             let engineConfigExtras = [ | |||
|  |                 "ad_platform": "test", | |||
|  |                 "ad_unit_id" : "112233", | |||
|  |                 "ad_amz_slot_id": "test_slot" | |||
|  |             ] | |||
|  |              | |||
|  |             let engine = sdk.createInterstitialAdEngine(adEngineConfig: AdEngineConfig(strategy: 0, faUnitId: "default", config: engineConfigExtras)) | |||
|  |              | |||
|  |             assert(engine != nil, "engine is Nil") | |||
|  |             engine!.initialize() | |||
|  |             try await Task.sleep(nanoseconds: 1000_000_000) | |||
|  |             assert(engine!.load(), "load failed!") | |||
|  |             try await Task.sleep(nanoseconds: 1000_000_000) | |||
|  |             assert(engine!.show(InterstitialShowRequest(placement: "1234_mock")), "show failed!") | |||
|  |             try await Task.sleep(nanoseconds: 1000_000_000) | |||
|  |             assert(engine!.destroy(), "destroy failed!") | |||
|  |         } | |||
|  |     } | |||
|  |      | |||
|  |     func testMaxEngine() { | |||
|  |         testPlatformEngine(adPlatform: AdPlatform.max, adUnitId: "87a262be42a9b334") | |||
|  |     } | |||
|  |      | |||
|  |     func testIronSourceEngine() { | |||
|  |         testPlatformEngine(adPlatform: AdPlatform.ironSource, adUnitId: "wmgt0712uuux8ju4") | |||
|  |     } | |||
|  |      | |||
|  |     func testAdMobEngine() { | |||
|  |         testPlatformEngine(adPlatform: AdPlatform.adMob, adUnitId: "ca-app-pub-3940256099942544/4411468910") | |||
|  |     } | |||
|  |      | |||
|  |     var logger: FileLogHandler? = nil | |||
|  |     var rotationLogger: FileLogHandler? = nil | |||
|  |     var levelLogger: FileLogHandler? = nil | |||
|  |     var manualRotationLogger: FileLogHandler? = nil | |||
|  |      | |||
|  |     func testLogging() { | |||
|  |         print("开始测试 FileLogHandler...") | |||
|  |         let fileManager = FileManager.default | |||
|  |          // 创建测试目录 | |||
|  |         let documentsDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first! | |||
|  |          let testLogDir = documentsDir.appendingPathComponent("Logs/guru_app", isDirectory: true) | |||
|  |           | |||
|  |          // 测试案例1: 基本日志记录 | |||
|  |          print("测试1: 基本日志记录") | |||
|  |          let logger = FileLogHandler(directory: "guru_app", filename: "test.log") | |||
|  |         logger.log("test", "这是一条调试消息", level: .debug) | |||
|  |         logger.log("test", "这是一条信息消息", level: .info) | |||
|  |         logger.log("test", "这是一条警告消息", level: .warning) | |||
|  |         logger.log("test", "这是一条错误消息", level: .error) | |||
|  |         logger.log("test", "这是一条致命消息", level: .fatal) | |||
|  |          logger.log("test", "自定义日志级别消息", level: .info) | |||
|  |         self.logger = logger | |||
|  |          print("基本日志写入完成,日志文件位置: \(testLogDir.appendingPathComponent("test.log").path)") | |||
|  |          | |||
|  |          | |||
|  |          // 测试案例3: 日志轮转 | |||
|  |          print("测试3: 测试日志轮转") | |||
|  |          let rotationConfig = FileLogHandler.RotationConfig( | |||
|  |              maxFileSize: 1024, // 1KB,设置小一点以便测试轮转 | |||
|  |              maxBackupCount: 3  // 保留3个备份 | |||
|  |          ) | |||
|  |          let rotationLogger = FileLogHandler( | |||
|  |              directory: "guru_app", | |||
|  |              filename: "rotation_test.log", | |||
|  |              rotationConfig: rotationConfig | |||
|  |          ) | |||
|  |         self.rotationLogger = rotationLogger | |||
|  |           | |||
|  |          // 写入足够多的数据以触发轮转 | |||
|  |          print("写入数据以触发日志轮转...") | |||
|  |          for i in 1...100 { | |||
|  |              rotationLogger.log("test", "这是日志条目 #\(i): " + String(repeating: "测试数据 ", count: 10), level: .info) | |||
|  |          } | |||
|  |           | |||
|  |          // 验证轮转后的文件 | |||
|  |          if let files = try? fileManager.contentsOfDirectory(atPath: testLogDir.path) { | |||
|  |              let rotationFiles = files.filter { $0.starts(with: "rotation_test.log") } | |||
|  |              print("找到的轮转日志文件: \(rotationFiles)") | |||
|  |          } | |||
|  |           | |||
|  |          // 测试案例4: 自定义级别过滤 | |||
|  |          print("测试4: 日志级别过滤") | |||
|  |          let levelLogger = FileLogHandler( | |||
|  |             directory: "guru_app", | |||
|  |             filename: "level_test.log", | |||
|  |              minimumLogLevel: .warning | |||
|  |          ) | |||
|  |         self.levelLogger = levelLogger | |||
|  |           | |||
|  |         levelLogger.log("level_test", "这是一条调试消息", level: .debug) | |||
|  |         levelLogger.log("level_test", "这是一条信息消息", level: .info) | |||
|  |         levelLogger.log("level_test", "这是一条警告消息", level: .warning) | |||
|  |         levelLogger.log("level_test", "这是一条错误消息", level: .error) | |||
|  |         levelLogger.log("level_test", "这是一条致命消息", level: .fatal) | |||
|  |         levelLogger.log("level_test", "自定义日志级别消息", level: .info) | |||
|  |          print("级别过滤测试完成") | |||
|  |           | |||
|  |          // 测试案例5: 手动轮转 | |||
|  |          print("测试5: 手动轮转") | |||
|  |          let manualRotationLogger = FileLogHandler(directory: "guru_app", filename: "manual_rotation.log") | |||
|  |          manualRotationLogger.log("test", "轮转前的日志条目") | |||
|  |          manualRotationLogger.rotateLogFile() | |||
|  |          manualRotationLogger.log("test", "轮转后的日志条目") | |||
|  |          print("手动轮转测试完成") | |||
|  |         self.manualRotationLogger = manualRotationLogger | |||
|  |           | |||
|  |          // 测试案例6: 轮转后继续写入 | |||
|  |          print("测试6: 轮转后继续写入") | |||
|  |          for i in 1...5 { | |||
|  |              rotationLogger.log("test", "轮转后的日志条目 #\(i)") | |||
|  |          } | |||
|  |          print("轮转后写入测试完成") | |||
|  |           | |||
|  |          // 读取日志文件内容进行验证 | |||
|  |          func readLogFile(at path: String) -> String? { | |||
|  |              return try? String(contentsOfFile: path, encoding: .utf8) | |||
|  |          } | |||
|  |          if let logContent = readLogFile(at: testLogDir.appendingPathComponent("test.log").path) { | |||
|  |              print("基本日志文件的前200个字符:") | |||
|  |              print(String(logContent.prefix(200))) | |||
|  |          } | |||
|  |           | |||
|  |          print("FileLogHandler 测试完成") | |||
|  |      } | |||
|  |      | |||
|  |      | |||
|  |     func testPlatformEngine(adPlatform: AdPlatform, adUnitId: String) { | |||
|  |         Task {@MainActor in | |||
|  |             let sdk = FusionAdsSdk(controller: self) | |||
|  |             let result = await sdk.initialize(adsProfile: AdsProfile(adPlatforms:[adPlatform], maxSdkKey: "V5I0i-vOTXkc_HEyqLg0lNm_ivlzp1wPVF3Vs7Jk4ix6WMAwEKGHMpugavZp_7xgss186Frvss23NGSWZXSago", ironSourceSdkKey: "8545d445")) | |||
|  |             assert(result, "sdk initialized success!") | |||
|  |              | |||
|  |             let engineConfigExtras = [ | |||
|  |                 "ad_platform": adPlatform.name, | |||
|  |                 "ad_unit_id" : adUnitId, | |||
|  |             ] | |||
|  |              | |||
|  |             let engine = sdk.createInterstitialAdEngine(adEngineConfig: AdEngineConfig(strategy: 0, faUnitId: "default", config: engineConfigExtras)) | |||
|  |              | |||
|  |             assert(engine != nil, "engine is Nil") | |||
|  |             engine!.initialize() | |||
|  |             try await Task.sleep(nanoseconds: 1000_000_000) | |||
|  |             assert(engine!.load(), "load failed!") | |||
|  |             try await Task.sleep(nanoseconds: 20_000_000_000) | |||
|  |             assert(engine!.currentStateIdentifier == InterstitialAdEngine.AdState.Identifier.LOADED, "not loaded after 20s, current state is \(engine!.currentStateIdentifier.name)") | |||
|  |             assert(engine!.show(InterstitialShowRequest(placement: "1234_mock")), "show failed!") | |||
|  |             try await Task.sleep(nanoseconds: 5000_000_000) | |||
|  |             assert(engine!.destroy(), "destroy failed!") | |||
|  |         } | |||
|  |     } | |||
|  |      | |||
|  |     func testMaxOfWithSameValue() { | |||
|  |         let list = [TestValue("A", 1), TestValue("B", 2), TestValue("C", 3), TestValue("D", 3)] | |||
|  |          | |||
|  |         let value = list.max(by: { $0.value <= $1.value }) | |||
|  |          | |||
|  |         assert(value?.name == "D") | |||
|  |         print("Yes!") | |||
|  |     } | |||
|  | 
 | |||
|  |     override func didReceiveMemoryWarning() { | |||
|  |         super.didReceiveMemoryWarning() | |||
|  |         // Dispose of any resources that can be recreated. | |||
|  |     } | |||
|  | } | |||
|  | 
 | |||
|  | private struct TestValue { | |||
|  |     let name: String; | |||
|  |     let value: Int; | |||
|  |      | |||
|  |     init(_ name: String, _ value: Int) { | |||
|  |         self.name = name | |||
|  |         self.value = value | |||
|  |     } | |||
|  | } |