155 lines
5.1 KiB
Swift
155 lines
5.1 KiB
Swift
import Flutter
|
||
import UIKit
|
||
import ScreenTime
|
||
|
||
@available(iOS 14.0, *)
|
||
public class TimeTrackingPlugin: NSObject, FlutterPlugin {
|
||
public static func register(with registrar: FlutterPluginRegistrar) {
|
||
let channel = FlutterMethodChannel(
|
||
name: "autotime_tracker/time_tracking",
|
||
binaryMessenger: registrar.messenger()
|
||
)
|
||
let instance = TimeTrackingPlugin()
|
||
registrar.addMethodCallDelegate(instance, channel: channel)
|
||
}
|
||
|
||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||
switch call.method {
|
||
case "hasPermission":
|
||
hasPermission(result: result)
|
||
case "requestPermission":
|
||
requestPermission(result: result)
|
||
case "getAppUsage":
|
||
getAppUsage(call: call, result: result)
|
||
case "startBackgroundTracking":
|
||
startBackgroundTracking(result: result)
|
||
case "stopBackgroundTracking":
|
||
stopBackgroundTracking(result: result)
|
||
case "isBackgroundTrackingActive":
|
||
isBackgroundTrackingActive(result: result)
|
||
default:
|
||
result(FlutterMethodNotImplemented)
|
||
}
|
||
}
|
||
|
||
// MARK: - Permission Methods
|
||
|
||
private func hasPermission(result: @escaping FlutterResult) {
|
||
if #available(iOS 14.0, *) {
|
||
let authorizationStatus = STScreenTime.getAuthorizationStatus()
|
||
result(authorizationStatus == .authorized)
|
||
} else {
|
||
result(false)
|
||
}
|
||
}
|
||
|
||
private func requestPermission(result: @escaping FlutterResult) {
|
||
if #available(iOS 14.0, *) {
|
||
STScreenTime.requestAuthorization { success, error in
|
||
if let error = error {
|
||
result(FlutterError(
|
||
code: "AUTHORIZATION_FAILED",
|
||
message: error.localizedDescription,
|
||
details: nil
|
||
))
|
||
} else {
|
||
result(success)
|
||
}
|
||
}
|
||
} else {
|
||
result(FlutterError(
|
||
code: "UNSUPPORTED_VERSION",
|
||
message: "Screen Time API requires iOS 14.0 or later",
|
||
details: nil
|
||
))
|
||
}
|
||
}
|
||
|
||
// MARK: - App Usage Methods
|
||
|
||
@available(iOS 14.0, *)
|
||
private func getAppUsage(call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||
guard let args = call.arguments as? [String: Any],
|
||
let startTimeMs = args["startTime"] as? Int64,
|
||
let endTimeMs = args["endTime"] as? Int64 else {
|
||
result(FlutterError(
|
||
code: "INVALID_ARGUMENTS",
|
||
message: "Invalid arguments",
|
||
details: nil
|
||
))
|
||
return
|
||
}
|
||
|
||
let startTime = Date(timeIntervalSince1970: Double(startTimeMs) / 1000.0)
|
||
let endTime = Date(timeIntervalSince1970: Double(endTimeMs) / 1000.0)
|
||
|
||
// 检查权限
|
||
guard STScreenTime.getAuthorizationStatus() == .authorized else {
|
||
result(FlutterError(
|
||
code: "PERMISSION_DENIED",
|
||
message: "Screen Time permission not granted",
|
||
details: nil
|
||
))
|
||
return
|
||
}
|
||
|
||
// 获取应用使用数据
|
||
STScreenTime.getAppUsage(from: startTime, to: endTime) { usage, error in
|
||
if let error = error {
|
||
result(FlutterError(
|
||
code: "GET_USAGE_FAILED",
|
||
message: error.localizedDescription,
|
||
details: nil
|
||
))
|
||
return
|
||
}
|
||
|
||
guard let usage = usage else {
|
||
result([])
|
||
return
|
||
}
|
||
|
||
// 转换为 Flutter 可用的格式
|
||
var appUsageList: [[String: Any]] = []
|
||
|
||
// 遍历应用使用数据
|
||
// 注意:实际的 Screen Time API 使用方式可能不同
|
||
// 这里提供基本框架,需要根据实际 API 调整
|
||
|
||
// 示例数据结构
|
||
for (bundleId, timeInterval) in usage {
|
||
let appName = Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ?? bundleId
|
||
|
||
appUsageList.append([
|
||
"packageName": bundleId,
|
||
"appName": appName,
|
||
"startTime": startTime.timeIntervalSince1970 * 1000,
|
||
"endTime": endTime.timeIntervalSince1970 * 1000,
|
||
"duration": Int(timeInterval),
|
||
"deviceUnlockCount": 0
|
||
])
|
||
}
|
||
|
||
result(appUsageList)
|
||
}
|
||
}
|
||
|
||
// MARK: - Background Tracking Methods
|
||
|
||
private func startBackgroundTracking(result: @escaping FlutterResult) {
|
||
// iOS 后台追踪实现
|
||
// 注意:iOS 对后台运行有严格限制
|
||
// 可以使用 Background Tasks 或 Notification Service Extension
|
||
result(true)
|
||
}
|
||
|
||
private func stopBackgroundTracking(result: @escaping FlutterResult) {
|
||
result(true)
|
||
}
|
||
|
||
private func isBackgroundTrackingActive(result: @escaping FlutterResult) {
|
||
result(false)
|
||
}
|
||
}
|
||
|