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:
My questions are as follows:
- Since I'm using UIKit and SwiftUI, I can't use the
.task
modifier. So I created an asynchronous task inviewDidLoad()
to configure the group activity session instead. Is this the proper way of doing things, or is there a better way? - 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?