swiftwwdcios15xcode13macos-monterey

How to write a UIKit app incorporating the GroupActivities framework


I have watched Apple's WWDC 2021 video on how to write an iOS app with custom group activities, link here.

After watching this video I tried to write a simple app of my own, using UIKit instead of SwiftUI. It's a simple app that uses a UIAlert to add Strings to a UITableView. I wrote it using Xcode 13 beta 4 running on macOS Monterey beta 4. It seems to work fine on my MacBook but I don't have a device running iOS 15 beta 4 to test, and it won't work in the simulator. Hope to test it soon.

In the meantime, I thought I'd share the code. It's a simple app, and there is only one view controller, and here's the code in it:

//
//  ViewController.swift
//  ShareOrder
//
//  Created by iOS 15 Programming on 28/07/2021.
//

import UIKit
import GroupActivities

class ViewController: UIViewController {
    
    var orders: [String] = []
    var groupSession: GroupSession<ShareOrder>?
    var messenger: GroupSessionMessenger?
    
    @IBOutlet var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        title = "ShareOrder"
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "orderCell")
        Task {
            for await session in ShareOrder.sessions(){
                configureGroupSession(session)
            }
        }
    }
    
    @IBAction func activateGroupActivity(_ sender: Any) {
        ShareOrder().activate()
    }
    
    @IBAction func addOrder(_ sender: UIBarButtonItem) {
        
        let alert = UIAlertController(title: "New Order", message: "Add a new order", preferredStyle: .alert)
        
        let saveAction = UIAlertAction(title: "Save", style: .default) {
            [unowned self] action in
            guard let textField = alert.textFields?.first, let orderToSave = textField.text else {
                return
            }
            self.orders.append(orderToSave)
            if let messenger = messenger {
                Task {
                    do {
                        try await messenger.send(orderToSave)
                    } catch {
                        print("Failed to send")
                    }
                }
            }
            self.tableView.reloadData()
        }
        
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
        
        alert.addTextField()
        alert.addAction(saveAction)
        alert.addAction(cancelAction)
        present(alert, animated: true)
    }
    
}

extension ViewController: UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        orders.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "orderCell", for: indexPath)
        cell.textLabel?.text = orders[indexPath.row]
        return cell
    }
    
}

extension ViewController {
    
    struct ShareOrder: GroupActivity {
        var metadata: GroupActivityMetadata {
            var metadata = GroupActivityMetadata()
            metadata.title = NSLocalizedString("Share Order", comment: "Title of group activity")
            metadata.type = .generic
            return metadata
        }
    }
    
    func configureGroupSession(_ groupSession: GroupSession<ShareOrder>) {
        orders.removeAll()
        self.groupSession = groupSession
        let messenger = GroupSessionMessenger(session: groupSession)
        self.messenger = messenger
        Task.detached { [weak self] in
            for await (message, _) in messenger.messages(of: String.self) {
                await self?.handle(message)
            }
        }
        groupSession.join()
    }
    
    func handle(_ message: String) {
        self.orders.append(message)
        self.tableView.reloadData()
    }
}

You can download it here:

ShareOrder app

My questions are as follows:

  1. Since I'm using UIKit and SwiftUI, I can't use the .task modifier. So I created an asynchronous task in viewDidLoad() to configure the group activity session instead. Is this the proper way of doing things, or is there a better way?
  2. All I need to test is to have two devices running iOS 15 b4 with the same app installed, or one Mac running MacOS 12 b4 and one iOS device running iOS 15 b4, correct?

Solution

  • Have tested my app and it works!

    1. Don't know if this is still the best solution, but creating an asynchronous task in viewDidLoad() did work for me.
    2. Yes. I tested my app on an Intel Mac running macOS 12 b4 and an iPhone SE running iOS 15 b4.