screen time api - FamilyActivityPicker 获取选中应用

使用 FamilyActivityPicker 获取选中应用的详细信息

在 iOS 15+ 中,FamilyActivityPicker 是家庭控制功能的重要组成部分,允许用户选择要监控或限制的应用。但选择后如何获取应用的详细信息(如图标、名称等)呢?本文将详细介绍相关 API 和使用方法。

相关 API 介绍

1. FamilyActivitySelection

  • 作用:表示用户选择的应用程序、网站或类别的集合
  • 包含属性
    • applications:选中的应用程序集合
    • categories:选中的应用类别集合
    • webDomains:选中的网站域名集合

2. Application

  • 作用:代表一个具体的应用程序
  • 关键属性
    • token:应用的唯一标识符
    • localizedDisplayName:本地化的应用名称
    • bundleIdentifier:应用的 Bundle ID

3. AppMetadata

  • 作用:提供应用程序的元数据信息
  • 获取方式 :通过 AppMetadata(token:) 初始化器

实现步骤

步骤 1:创建状态管理

swift 复制代码
import SwiftUI
import FamilyControls

struct ContentView: View {
    @State private var selection = FamilyActivitySelection()
    @State private var selectedApps: [AppInfo] = []
    
    var body: some View {
        VStack {
            // 选择器
            FamilyActivityPicker(selection: $selection)
            
            // 显示选中应用信息
            List(selectedApps, id: \.bundleIdentifier) { app in
                HStack {
                    if let image = app.icon {
                        Image(uiImage: image)
                            .resizable()
                            .frame(width: 40, height: 40)
                            .cornerable(8)
                    }
                    VStack(alignment: .leading) {
                        Text(app.name)
                            .font(.headline)
                        Text(app.bundleIdentifier)
                            .font(.caption)
                            .foregroundColor(.gray)
                    }
                }
            }
        }
        .onChange(of: selection) { newValue in
            loadSelectedAppsInfo()
        }
    }
}

步骤 2:定义应用信息模型

swift 复制代码
struct AppInfo {
    let token: ApplicationToken
    let name: String
    let bundleIdentifier: String
    let icon: UIImage?
}

步骤 3:加载应用详细信息

swift 复制代码
extension ContentView {
    private func loadSelectedAppsInfo() {
        selectedApps.removeAll()
        
        // 遍历选中的所有应用
        for application in selection.applications {
            let appInfo = createAppInfo(from: application)
            selectedApps.append(appInfo)
        }
    }
    
    private func createAppInfo(from application: Application) -> AppInfo {
        // 获取应用显示名称
        let displayName = application.localizedDisplayName ?? "未知应用"
        
        // 获取 Bundle Identifier
        let bundleID = application.bundleIdentifier ?? "未知 Bundle ID"
        
        // 获取应用图标
        let appIcon = loadAppIcon(for: application.token)
        
        return AppInfo(
            token: application.token,
            name: displayName,
            bundleIdentifier: bundleID,
            icon: appIcon
        )
    }
}

步骤 4:加载应用图标

swift 复制代码
extension ContentView {
    private func loadAppIcon(for token: ApplicationToken) -> UIImage? {
        do {
            // 通过 AppMetadata 获取应用信息
            let metadata = try AppMetadata(token: token)
            
            // 获取应用图标(需要处理权限和异步加载)
            // 注意:实际图标的获取可能需要额外的权限或使用其他方法
            return nil // 这里需要根据具体实现调整
            
        } catch {
            print("获取应用元数据失败: \(error)")
            return nil
        }
    }
}

完整示例代码

swift 复制代码
import SwiftUI
import FamilyControls

struct FamilyActivityAppView: View {
    @State private var selection = FamilyActivitySelection()
    @State private var selectedApps: [AppInfo] = []
    
    var body: some View {
        NavigationView {
            VStack(spacing: 20) {
                Text("选择要管理的应用")
                    .font(.title2)
                    .padding()
                
                FamilyActivityPicker(selection: $selection)
                    .frame(height: 300)
                
                Divider()
                
                Text("已选择的应用 (\(selectedApps.count))")
                    .font(.headline)
                
                List(selectedApps, id: \.bundleIdentifier) { app in
                    AppInfoRow(appInfo: app)
                }
                .listStyle(PlainListStyle())
            }
            .padding()
            .navigationTitle("应用管理")
        }
        .onChange(of: selection) { newValue in
            updateSelectedApps()
        }
    }
    
    private func updateSelectedApps() {
        Task {
            var apps: [AppInfo] = []
            
            for application in selection.applications {
                let appInfo = await createAppInfo(from: application)
                apps.append(appInfo)
            }
            
            await MainActor.run {
                selectedApps = apps
            }
        }
    }
    
    private func createAppInfo(from application: Application) async -> AppInfo {
        let displayName = application.localizedDisplayName ?? "未知应用"
        let bundleID = application.bundleIdentifier ?? "未知"
        
        // 异步加载应用图标
        let icon = await loadAppIcon(for: application.token)
        
        return AppInfo(
            token: application.token,
            name: displayName,
            bundleIdentifier: bundleID,
            icon: icon
        )
    }
    
    private func loadAppIcon(for token: ApplicationToken) async -> UIImage? {
        // 这里可以实现具体的图标加载逻辑
        // 可能需要使用其他系统 API 或第三方库
        return nil
    }
}

struct AppInfoRow: View {
    let appInfo: AppInfo
    
    var body: some View {
        HStack(spacing: 12) {
            if let image = appInfo.icon {
                Image(uiImage: image)
                    .resizable()
                    .frame(width: 40, height: 40)
                    .cornerRadius(8)
            } else {
                Rectangle()
                    .fill(Color.gray.opacity(0.3))
                    .frame(width: 40, height: 40)
                    .cornerRadius(8)
                    .overlay(
                        Image(systemName: "app")
                            .foregroundColor(.gray)
                    )
            }
            
            VStack(alignment: .leading, spacing: 4) {
                Text(appInfo.name)
                    .font(.headline)
                Text(appInfo.bundleIdentifier)
                    .font(.caption)
                    .foregroundColor(.secondary)
            }
            
            Spacer()
        }
        .padding(.vertical, 4)
    }
}

struct AppInfo {
    let token: ApplicationToken
    let name: String
    let bundleIdentifier: String
    let icon: UIImage?
}

注意事项

  1. 权限要求 :使用 FamilyActivityPicker 需要申请相应的家庭控制权限
  2. 图标获取限制:直接获取其他应用的图标可能受到系统限制
  3. 异步处理:应用信息的加载建议使用异步方式,避免阻塞 UI
  4. 错误处理:妥善处理可能出现的异常情况

通过以上步骤,你可以成功获取用户选择的应用的详细信息,并在界面中展示出来。

这个实现提供了完整的解决方案,包括 API 介绍、实现步骤和完整代码示例。你可以根据实际需求进行调整和优化。

相关推荐
游戏开发爱好者827 分钟前
2025年iOS应用上架App Store全指南,开发者必看
android·ios·小程序·https·uni-app·iphone·webview
HH思️️无邪1 小时前
Flutter 项目 -从 0 到 1 实现 iOS WatchApp
flutter·ios
TheNextByte12 小时前
如何将 iPhone 上的联系人备份到 iCloud?
ios·iphone·icloud
牛马1113 小时前
iOS swift 自定义View
ios·cocoa·swift
2501_915106323 小时前
HBuilderX 项目上架 iOS app上架 App Store 的关键流程
android·ios·小程序·https·uni-app·iphone·webview
2501_915106323 小时前
iOS 文件管理,在不越狱的前提下管理 iPhone / iPad 文件
android·ios·小程序·uni-app·iphone·webview·ipad
牛马1113 小时前
ios swift处理json数据
ios·json·swift
黑码哥3 小时前
iOS开屏广告多机型屏幕适配最佳实践
macos·ios·cocoa·广告·商业·开屏广告
Swift社区4 小时前
LeetCode 473 火柴拼正方形 - Swift 题解
算法·leetcode·swift
前端不太难5 小时前
Flutter / RN / iOS,在长期维护下谁更容易“止损”?
flutter·ios·状态模式