Я должен начать эту статью с отказа от ответственности, она основана на iOS 13, Swift 5 и Xcode 11.x. Если вы читаете это и эти цифры выглядят устаревшими, будьте предупреждены.

Я также должен предупредить вас, что уведомления и код iCloud связаны с инфраструктурой Apple, а это означает, что для их использования вам потребуется учетная запись Apple Developers.

Наконец, очевидно, что это часть IV, вам нужно вернуться к части I, части II и части II, чтобы это имело какой-то смысл, действительно, вам нужно просмотреть серию уведомлений, прежде чем делать это, иначе ваша борьба.

Мы почти готовы к еще одному испытанию. Вам просто нужно внести еще несколько изменений. Начните с ContentView.swift и добавьте этот код.

TextField("Message", text: $yourMessageHere, onCommit: {
self.output = self.yourMessageHere
cloud.fetchRecords(name: self.sendingTo!)
}).onReceive(cloudPublisher, perform: { (data) in
print("data ",data)
poster.postNotification(token: data, message: self.yourMessageHere)
})
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()

Я включил всю суть, у вас уже есть TextField, вам просто нужно добавить к нему эти методы. А теперь к файлу Cloud.swift.

func fetchRecords(name: String) {
print("fetch ",name)
let predicate = NSPredicate(format: "name = %@", name)
let query = CKQuery(recordType: "mediator", predicate: predicate)
publicDB.perform(query,inZoneWith: CKRecordZone.default().zoneID) { [weak self] results, error in
guard let _ = self else { return }
if let error = error {
DispatchQueue.main.async {
print("error",error)
}
return
}
guard let results = results else { return }
for result in results {
print("results ",result)
let rex = result.object(forKey: "senderDevice") as? String
print("rex ",rex)
DispatchQueue.main.async {
cloudPublisher.send(rex!)
}
}
if results.count == 0 {
print("no name ",name)
}
}
}

Это вызывается, когда вы пытаетесь отправить сообщение. Обратите внимание на фиксацию вызовов на iphone, когда вы убираете клавиатуру, но не на iPad. На iPad это вызывается, когда вы нажимаете клавишу возврата.

Хорошо, еще одно изменение. Вы могли заметить, что класс RemoteNotification не принимает никаких параметров. Нам нужно это исправить. Откройте его, измените код и внесите это изменение.

...
func postNotification(token:String, message:String) {
let jsonObject: [String: Any] = ["aps":["sound":"bingbong.aiff","badge":1,"alert":message]]

И с этим, если я не забыл, вы сможете снова протестировать его, хотя теперь вам понадобятся два устройства iOS. Поместите их оба, скомпилируйте и запустите на обоих.

Установите первое как устройство Люка, отправив Марку. Второй как устройство Марка, отправляющее Люку. Введите сообщение в устройство Люка, и если сила с вами :), оно должно появиться на устройстве Марка. Попробуйте наоборот.

Бон, если все работает, мы ничего не забыли! Если не удачи с отладкой :) нет, серьезно, мы еще не закончили. Мы пропустили безопасность, чтобы упростить отладку. Теперь нам нужно реализовать безопасность.

Теперь я должен признать, что здесь есть / была ошибка, которая все еще здесь, которая сбила меня с толку на несколько часов. У меня фантастическая ошибка, на которую вы обратите внимание, если ваш учитель приведет к этому отличный пример. Но прежде чем я расскажу об этом, вот код. Верхнее колесо выбора выглядит так.

.onTapGesture {
let success = rsa.generateKeyPair(keySize: 2048, privateTag: "ch.cqd.noob", publicTag: "ch.cqd.noob")
if success {
let publicK = rsa.getPublicKey()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let token = appDelegate.returnToken()
cloud.searchAndUpdate(name: self.users[self.selected], publicK: publicK!, device: token)
self.sender = self.users[self.selected]
messagePublisher.send(self.sender + " Logged In")
self.disableUpperWheel = true
}

Нижнее колесо выбора выглядит так.

.onReceive(dataPublisher) { (data) in
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let token = appDelegate.returnToken()
self.sendingTo = self.users[self.selected2]
// self.sending person selected in second PickerView
// self.sender person selected in first PickerView sending message
// token device sender [this device] is running on encypted with sending person public key
rsa.putPublicKey(publicK: data, blockSize: 2048, keySize: 2048, privateTag: "ch.cqd.noob", publicTag: "ch.cqd.noob")
let encryptedToken = rsa.encrypt(text: token)
messagePublisher.send("Sending To " + self.sendingTo)
cloud.keepRec(name: self.sender, sender: self.sendingTo, senderDevice: token, encryptedDevice: "", token: encryptedToken)
self.disableLowerWheel = true
}

А отправка сообщения выглядит так.

.onTapGesture {
cloud.search(name: self.users[self.selected2])
}.onReceive(cloudPublisher, perform: { (data) in
let token2Send = rsa.decprypt(encrpted: data)
print("data ",data,token2Send)
poster.postNotification(token: token2Send!, message: self.yourMessageHere)
})

Как это работает. Ну, как и раньше, вы утверждаете право собственности на свое устройство, а затем говорите, кому вы хотите отправить сообщение. Он также ищет человека, которому вы хотите отправить сообщение, и шифрует токен вашего устройства в файле обмена с помощью его открытого ключа.

На их стороне вы повторяете тот же процесс. Они забирают свое устройство и соглашаются отправлять вам сообщения. Он шифрует их токен с помощью вашего открытого ключа и сохраняет его, чтобы вы могли его забрать и отправить обратно.

Теперь, когда вы хотите отправить сообщение, он использует ваш закрытый ключ, который ему известен, потому что он только что создал пару ключей для расшифровки токена, который вы зашифровали с помощью открытого ключа на другой стороне, которую вы искали.

Но ОСТАНОВИТЕСЬ, и вот незаметная ошибка. И последовательность, в которой вы сделали то, что я только что попросил вас сделать, покажет себя или нет. Если у вас произошел сбой, попробуйте еще раз, но внимательно следуйте этой последовательности.

Теперь сделайте резервную копию и перезапустите. Остановите приложение и очистите базу данных, удалите обе записи meditor.

Запустите приложение на устройстве A и устройстве B. Выберите пользователя, который будет заявлять права на устройство A. Выберите пользователя, который заявит права на устройство B, а затем выберите пользователей, которым вы хотите отправить сообщение на устройстве A и устройстве B. Это сработает.

Вы можете заметить разницу. Читать дальше.