避坑!OC 项目的灵动岛开发

486 阅读3分钟

iOS16.1系统开始正式支持实时活动,更新Xcode为最新的14.1版本,(跟着官方文档步骤)开始着手开发

提示:项目是OC项目,且这次实时活动用到了用到远程推送

image.png

CleanShot 2024-07-30 at 17.11.21.png

1.新建OC项目,Info-Plist文件加入Bool类型的权限key值为:Supports Live Activities value为:YES
2.如果项目之前有过小组件,则不需要再创建新的Widget-Extension,直接在@main WidgetBundle里面添加要创建的Live-Activity组件即可(我们在后面添加)
3.(我是OC项目)在主项目里面新建一个MyLiveActivityAttributes.swift
struct MyLiveActivityAttributes: ActivityAttributes {

    typealias EasyDriveOrderState = ContentState

    public struct ContentState: Codable, Hashable {

        var orderId: Int?

        var subOrderType: Int?

        var status: Int?

        var startTime: String?

        var endTime: String?

        var startCode: Int?

        var studentName: String?

        var studentAvatar: String?

        var userName: String?

        var userAvatar: String?

        var courseName: String?

        var isSendToken: Int?

        var lessonLeftTime:Int?

        var isMicrophonePermissionGranted: Int?

    }

 
    var contentState: ContentState

    init(MyOrderData: MyOrderData) {

        self.contentState = ContentState(

            orderId: MyOrderData.orderId,

            subOrderType: MyOrderData.subOrderType,

            status: MyOrderData.status,

            startTime: MyOrderData.startTime,

            endTime: MyOrderData.endTime,

            startCode: MyOrderData.startCode,

            studentName: MyOrderData.studentName,

            studentAvatar: MyOrderData.studentAvatar,

            userName: MyOrderData.userName,

            userAvatar: MyOrderData.userAvatar,

            courseName: MyOrderData.courseName,

            isSendToken: MyOrderData.isSendToken,

            lessonLeftTime: MyOrderData.lessonLeftTime,

        )

    }

}

struct MyOrderData: Codable {

    let orderId: Int?

    let subOrderType: Int?

    let status: Int?

    let startTime: String?

    let endTime: String?

    let startCode: Int?

    let studentName: String?

    let studentAvatar: String?

    let userName: String?

    let userAvatar: String?

    let courseName: String?

    let isSendToken: Int?

    let lessonLeftTime: Int?

    

  


    enum CodingKeys: String, CodingKey {

        case orderId = "order_id"

        case subOrderType = "sub_order_type"

        case status = "status"

        case startTime = "start_time"

        case endTime = "end_time"

        case startCode = "start_code"

        case studentName = "student_name"

        case studentAvatar = "student_avatar"

        case userName = "user_name"

        case userAvatar = "user_avatar"

        case courseName = "course_name"

        case isSendToken = "is_send_token"

        case lessonLeftTime = "lesson_left_time"

    }

}

func parseMyOrderData(jsonData: Data) -> MyOrderData? {

    let decoder = JSONDecoder()

    do {

        let MyOrderData = try decoder.decode(MyOrderData.self, from: jsonData)

        return MyOrderData

    } catch {

        print("Error decoding JSON: \(error)")

        return nil

    }

}
4.(我是OC项目)在主项目里面新建一个MyLiveActivityManager.swift

自动生成OC Swift 桥接文件


@available(iOS 16.1, *)

@objcMembers

class MyLiveActivityManager: NSObject {

    

    static let shared = MyLiveActivityManager()

    

    private override init() { }

    

    var liveActivity: Activity<CoachLiveActivityAttributes>?

    var isActivityRunning = false

    

    @available(iOS 16.1, *)

    func startLiveActivity(data: [String: Any], completion: @escaping (String?) -> Void) async {

            guard let jsonData = try? JSONSerialization.data(withJSONObject: data, options: []),

                  let orderData = parseOrderData(jsonData: jsonData) else {

                print("Missing or invalid arguments")

                completion(nil)

                return

            }

            

        if(self.isActivityRunning || Activity<CoachLiveActivityAttributes>.activities.count > 0){

            

            print("count=====\(Activity<CoachLiveActivityAttributes>.activities.count)")

            

            print("Activity updateLiveActivity 内 \(data)")

            

            self.updateLiveActivity(data: data)

            

        }else{

            

            let attributes = CoachLiveActivityAttributes(orderData: orderData)

            

            do {

                

                print("Activity startLiveActivity 内\(data)")

                

                let activity = try Activity.request(attributes: attributes, contentState: attributes.contentState, pushType: .token)

                self.liveActivity = activity

                self.isActivityRunning = true

                Task {

                    do {

                        

                        print("Activity request========")

                        
获取Token 给后台实时推送
                        if let pushTokenUpdates = self.liveActivity?.pushTokenUpdates {

                            for await data in pushTokenUpdates {

                                let token = data.map { String(format: "%02x", $0) }.joined()

                                print("Received push token: \(token)")

                                completion(token)

                                return

                            }

                        }

                    

                    } catch {

                        completion("")

                    }

                }

                Task {

                    for await state in activity.activityStateUpdates {

                        if (state == .active) {

                            /// The Live Activity is active, visible to the user, and can receive content updates.

                            print("device-----活动active")

                            isActivityRunning = true

                        } else if (state == .ended) {

                            print("device-----活动ended")

                            isActivityRunning = false

                            /// The Live Activity is visible, but the user, app, or system ended it, and it won't update its content anymore.

                        } else { // .dismissed

                            /// The Live Activity ended and is no longer visible because the user or the system removed it.

                            print("device-----活动dismissed")

                            isActivityRunning = false

                        }

                    }

            }

                

            } catch let error {

                print("can't launch live activity: \(error.localizedDescription)")

                completion("")

            }

        }

    

}


    func updateLiveActivity(data: [String: Any]) -> Bool {

        guard let jsonData = try? JSONSerialization.data(withJSONObject: data, options: []),

              let orderData = parseOrderData(jsonData: jsonData) else {

            print("Missing or invalid arguments")

            return false

        }

        

        let attributes = CoachLiveActivityAttributes(orderData: orderData)


        print("Activity updateLiveActivity 内\(data)")

       
        Task {

            do {

                await liveActivity?.update(using: attributes.contentState)

                print("Activity updated successfully")

                return true

            } catch {

                print("Failed to update live activity: \(error)")

                return false

            }

        }

        return false

    }

    

    

    func endLiveActivity(data: [String: Any], completion: @escaping (Bool) -> Void) {

        guard let jsonData = try? JSONSerialization.data(withJSONObject: data, options: []),

              let orderData = parseOrderData(jsonData: jsonData) else {

            print("Missing or invalid arguments")

            completion(false)

            return

        }

  


        let attributes = CoachLiveActivityAttributes(orderData: orderData)

    

        

        Task {

            do {

                await liveActivity?.end(using: attributes.contentState, dismissalPolicy: .immediate)

                

                self.isActivityRunning = false;

                print("Activity ended successfully")

                completion(true)

            } catch {

                print("Failed to end live activity: \(error)")

                completion(false)

            }

        }

    }

    func isLiveActivitySupported() -> Bool {

        return ActivityAuthorizationInfo().areActivitiesEnabled

    }

    

}
5.(我是OC项目)AppDelegate 调用
[[MyLiveActivityManager shared]startLiveActivityWithData:args completion:^(NSString * token) {

                    if (token) {

                        result(token);

                    } else {

                        result(@"");

                    }

                    

                    } completionHandler:^{

                                        

                }];

效果如上图完美避坑。