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
|
|||
|
|
}
|
|||
|
|
}
|