SiriKit'in Amaçları Uygulamanıza Uyacak mı? Öyleyse, Bunları Nasıl Kullanacağınız İşte

Yayınlanan: 2022-03-10
Kısa özet ↬ Geçen yıldan beri, bir uygulamaya Apple'ın önceden tanımlanmış kullanım örneklerinden birine uyuyorsa Siri desteği eklemek mümkün oldu. SiriKit'in işinize yarayıp yaramayacağını ve nasıl kullanılacağını öğrenin.

iOS 5'ten beri Siri, iPhone kullanıcılarının Apple uygulamalarıyla mesaj göndermesine, hatırlatıcı ayarlamasına ve restoran aramasına yardımcı oldu. iOS 10'dan başlayarak, Siri'yi bazı uygulamalarımızda da kullanabiliyoruz.

Bu işlevi kullanabilmek için uygulamanızın Apple'ın önceden tanımlanmış Siri "etki alanları ve amaçları"na uyması gerekir. Bu makalede, bunların ne olduğunu öğreneceğiz ve uygulamalarımızın bunları kullanıp kullanamayacağını göreceğiz. Yapılacaklar listesi yöneticisi olan basit bir uygulamayı ele alacağız ve Siri desteğinin nasıl ekleneceğini öğreneceğiz. Ayrıca, SiriKit ile tanıtılan yeni bir uzantı türü olan Intents uzantısı için Apple geliştirici web sitesinin yapılandırma ve Swift koduyla ilgili yönergelerini inceleyeceğiz.

Bu makalenin kodlama kısmına geldiğinizde, Xcode'a (en azından sürüm 9.x) ihtiyacınız olacak ve Swift'de iOS geliştirme hakkında bilgi sahibi olmanız iyi olur çünkü Siri'yi küçük bir çalışmaya ekleyeceğiz. uygulama. Apple'ın geliştirici web sitesinde bir uzantı kurma ve uygulamaya Siri uzantı kodunu ekleme adımlarını inceleyeceğiz.

"Hey Siri, Sana Neden İhtiyacım Var?"

Bazen telefonumu kanepemdeyken iki elim boşta kullanıyorum ve tüm dikkatimi ekrana verebiliyorum. Belki annemin doğum gününü planlamak için kız kardeşime mesaj atarım ya da Trello'daki bir soruyu yanıtlarım. Uygulamayı görebiliyorum. Ekrana dokunabilirim. yazabilirim.

Ama saatime bir mesaj geldiğinde kasabamda dolaşıp bir podcast dinliyor olabilirim. Telefonum cebimde ve yürürken kolayca cevap veremiyorum.

Atlamadan sonra daha fazlası! Aşağıdan okumaya devam edin ↓

Siri ile kulaklığımın kontrol düğmesini basılı tutup "Kız kardeşime saat ikide orada olacağımı mesaj at" diyebiliyorum. Siri, hareket halindeyken ve telefonunuza tam olarak veremediğinizde veya etkileşim küçük olduğunda harikadır, ancak birkaç dokunuş ve bir sürü yazma gerektirir.

Bu etkileşimler için Apple uygulamalarını kullanmak istersem bu sorun değil. Ancak mesajlaşma gibi bazı uygulama kategorilerinin çok popüler alternatifleri vardır. Yolculuk rezervasyonu yapmak veya bir restoranda masa ayırtmak gibi diğer etkinlikler, Apple'ın yerleşik uygulamalarıyla bile mümkün değildir, ancak Siri için mükemmeldir.

Apple'ın Sesli Asistanlara Yaklaşımı

Üçüncü taraf uygulamalarda Siri'yi etkinleştirmek için Apple, sesi kullanıcının sesinden alacak ve bir şekilde isteği yerine getirebilecek şekilde uygulamaya getirecek bir mekanizmaya karar vermek zorunda kaldı. Bunu mümkün kılmak için Apple, kullanıcının istekte uygulamanın adını belirtmesini ister, ancak isteğin geri kalanıyla ne yapacaklarına dair birkaç seçeneği vardı.

  • Uygulamaya bir ses dosyası göndermiş olabilir.
    Bu yaklaşımın yararı, uygulamanın, kullanıcının onun için sahip olabileceği herhangi bir isteği tam anlamıyla işlemeye çalışabilmesidir. Amazon veya Google, zaten gelişmiş ses tanıma hizmetlerine sahip oldukları için bu yaklaşımı beğenmiş olabilir. Ancak çoğu uygulama bunu çok kolay halledemez.
  • Konuşmayı metne çevirebilir ve gönderebilirdi.
    Pek çok uygulamada karmaşık doğal dil uygulamaları bulunmadığından, kullanıcının genellikle çok özel ifadelere bağlı kalması gerekir ve İngilizce olmayan desteğin uygulanması uygulama geliştiricisine bağlıdır.
  • Anladığınız cümlelerin bir listesini vermenizi isteyebilirdi.
    Bu mekanizma, Amazon'un Alexa ile yaptığına ("yetenekler" çerçevesinde) daha yakındır ve Alexa'nın şu anda SiriKit'in kaldırabileceğinden çok daha fazla kullanımını sağlar. Bir Alexa becerisinde, Alexa'nın sizin için dolduracağı yer tutucu değişkenlere sahip ifadeler sağlarsınız. Örneğin, "Alexa, bana $TIME$ - $REMINDER$ arasında hatırlat" - Alexa, bu ifadeyi kullanıcının söylediklerine karşı çalıştıracak ve size TIME ve REMINDER için değerleri söyleyecektir. Önceki mekanizmada olduğu gibi, geliştiricinin tüm çeviriyi yapması gerekiyor ve kullanıcı biraz farklı bir şey söylüyorsa çok fazla esneklik yok.
  • Parametrelerle bir istek listesi tanımlayabilir ve uygulamaya yapılandırılmış bir istek gönderebilir.
    Bu aslında Apple'ın yaptığı şeydir ve faydası, çeşitli dilleri destekleyebilmesi ve bir kullanıcının bir isteği ifade edebileceği tüm yolları anlamaya çalışmak için tüm işi yapmasıdır. En büyük dezavantajı, yalnızca Apple'ın tanımladığı istekler için işleyici uygulayabilmenizdir. Bu, örneğin bir mesajlaşma uygulamanız varsa harikadır, ancak bir müzik akışı hizmetiniz veya bir podcast oynatıcınız varsa, şu anda SiriKit'i kullanmanın hiçbir yolu yoktur.

Benzer şekilde, uygulamaların kullanıcıyla konuşmasının üç yolu vardır: sesle, dönüştürülen metinle veya söylemek istediğiniz şeyi ifade ederek ve sistemin onu ifade etmenin tam yolunu bulmasına izin vererek. Son çözüm (Apple'ın yaptığı) çeviri yükünü Apple'a yükler, ancak size bir şeyleri açıklamak için kendi sözcüklerinizi kullanmanın sınırlı yollarını sunar.

İşleyebileceğiniz istek türleri, SiriKit'in etki alanlarında ve amaçlarında tanımlanmıştır. Niyet, bir kişiye mesaj atmak veya bir fotoğraf bulmak gibi kullanıcının yapabileceği bir istek türüdür. Her niyetin bir parametre listesi vardır; örneğin, mesajlaşma bir kişi ve bir mesaj gerektirir.

Bir etki alanı, yalnızca ilgili amaçlardan oluşan bir gruptur. Bir metni okumak ve bir metin göndermek, hem mesajlaşma alanındadır. Bir yolculuk rezervasyonu yapmak ve bir konum almak, yolculuk rezervasyonu alanındadır. VoIP aramaları yapmak, antrenmanlara başlamak, fotoğraf aramak ve birkaç başka şey için alan adları vardır. SiriKit'in belgeleri, etki alanlarının ve amaçlarının tam listesini içerir.

Siri'nin ortak eleştirisi, istekleri Google ve Alexa kadar karşılayamayacak gibi görünmesi ve Apple'ın rakipleri tarafından etkinleştirilen üçüncü taraf ses ekosisteminin daha zengin olmasıdır.

Bu eleştirilere katılıyorum. Uygulamanız mevcut amaçlara uymuyorsa SiriKit'i kullanamazsınız ve yapabileceğiniz hiçbir şey yoktur. Uygulamanız uygun olsa bile, Siri'nin söylediği veya anladığı tüm kelimeleri kontrol edemezsiniz; Bu nedenle, uygulamanızdaki şeyler hakkında belirli bir konuşma tarzınız varsa, bunu her zaman Siri'ye öğretemezsiniz.

iOS geliştiricilerinin umudu, hem Apple'ın amaç listesini büyük ölçüde genişletmesi hem de doğal dil işlemesinin çok daha iyi hale gelmesidir. Bunu yaparsa, geliştiricilerin aynı şeyi söylemenin tüm yollarını tercüme etmek veya anlamak zorunda kalmadan çalışan bir sesli asistanımız olacak. Ve yapılandırılmış istekler için destek uygulamak aslında oldukça basittir - doğal bir dil ayrıştırıcısı oluşturmaktan çok daha kolaydır.

Niyet çerçevesinin bir diğer büyük yararı da Siri ve sesli isteklerle sınırlı olmamasıdır. Şimdi bile Haritalar uygulaması, uygulamanız için amaca dayalı bir istek oluşturabilir (örneğin, bir restoran rezervasyonu). Bunu programlı olarak yapar (ses veya doğal dilden değil). Apple, uygulamaların birbirlerinin açığa çıkan amaçlarını keşfetmesine izin verseydi, uygulamaların birlikte çalışması için çok daha iyi bir yolumuz olurdu (x-geri arama stili URL'lerin aksine).

Son olarak, amaç parametreler içeren yapılandırılmış bir istek olduğundan, bir uygulamanın parametrelerin eksik olduğunu veya bazı seçenekler arasında ayrım yapmak için yardıma ihtiyacı olduğunu ifade etmesinin basit bir yolu vardır. Ardından Siri, uygulamanın konuşmayı yürütmesine gerek kalmadan parametreleri çözmek için takip soruları sorabilir.

Yolculuk-Rezervasyon Alanı

Alan adlarını ve amaçları anlamak için, araç kiralama alanına bakalım. Bu, Siri'den size bir Lyft arabası almasını istemek için kullanacağınız alan adıdır.

Apple, nasıl araç talep edileceğini ve bunun hakkında nasıl bilgi alınacağını tanımlar, ancak aslında bu isteği gerçekten yerine getirebilecek yerleşik bir Apple uygulaması yoktur. Bu, SiriKit özellikli bir uygulamanın gerekli olduğu birkaç alandan biridir.

Amaçlardan birini sesli olarak veya doğrudan Haritalar'dan çağırabilirsiniz. Bu etki alanının amaçlarından bazıları şunlardır:

  • Araç talep edin
    Bir yolculuk rezervasyonu yapmak için bunu kullanın. Bir alma ve bırakma konumu sağlamanız gerekecek ve uygulamanın ayrıca partinizin boyutunu ve ne tür bir sürüş istediğinizi bilmesi gerekebilir. Örnek bir ifade, "Beni <appname> ile gezdirin" olabilir.
  • Yolculuğun durumunu al
    Bu amacı, talebinizin alınıp alınmadığını öğrenmek ve konumları da dahil olmak üzere araç ve sürücü hakkında bilgi almak için kullanın. Haritalar uygulaması bu amacı, size yaklaşan arabanın güncellenmiş bir görüntüsünü göstermek için kullanır.
  • sürüşü iptal et
    Rezervasyon yaptığınız bir yolculuğu iptal etmek için bunu kullanın.

Bu amaçlardan herhangi biri için Siri'nin daha fazla bilgiye ihtiyacı olabilir. Bir amaç işleyici uyguladığımızda göreceğiniz gibi, Intents uzantınız Siri'ye gerekli bir parametrenin eksik olduğunu söyleyebilir ve Siri, kullanıcıdan bunu ister.

Amaçların Haritalar tarafından programlı olarak çağrılabilmesi, amaçların gelecekte uygulamalar arası iletişimi nasıl mümkün kılabileceğini gösterir.

Not : Alan adlarının ve amaçlarının tam listesini Apple'ın geliştirici web sitesinde bulabilirsiniz. Ayrıca, araç rezervasyonu da dahil olmak üzere birçok alan ve amacın uygulandığı örnek bir Apple uygulaması da bulunmaktadır.

Uygulamanıza Listeler ve Notlar Etki Alanı Desteği Ekleme

Tamam, şimdi SiriKit'in temellerini anladığımıza göre, çok sayıda yapılandırma ve işlemek istediğiniz her amaç için bir sınıf içeren bir uygulamada Siri için nasıl destek ekleyeceğinizi görelim.

Bu makalenin geri kalanı, bir uygulamaya Siri desteği eklemek için ayrıntılı adımlardan oluşur. Yapmanız gereken beş üst düzey şey var:

  1. Apple'ın geliştirici web sitesinde yeni yetkilendirmelere sahip ön hazırlık profilleri oluşturarak uygulamaya yeni bir uzantı eklemeye hazırlanın.
  2. Yetkileri kullanmak için uygulamanızı ( plist aracılığıyla) yapılandırın.
  3. Bazı örnek kodlarla başlamak için Xcode'un şablonunu kullanın.
  4. Siri amacınızı desteklemek için kodu ekleyin.
  5. Siri'nin kelime dağarcığını plist s ile yapılandırın.

Endişelenmeyin: Yol boyunca uzantıları ve yetkileri açıklayarak bunların her birini inceleyeceğiz.

Yalnızca Siri bölümlerine odaklanmak için basit bir yapılacaklar listesi yöneticisi, List-o-Mat hazırladım.

List-o-Mat'ın bir demosunu gösteren hareketli bir GIF
List-o-Mat'ta liste yapma (Geniş önizleme)

List-o-Mat örneğinin tam kaynağını GitHub'da bulabilirsiniz.

Bunu oluşturmak için tek yaptığım Xcode Master-Detail uygulama şablonuyla başlamak ve her iki ekranı da UITableView haline getirmekti. Listeleri ve öğeleri eklemenin ve silmenin bir yolunu ve öğeleri tamamlandı olarak işaretlemenin bir yolunu ekledim. Tüm gezinme şablon tarafından oluşturulur.

Verileri depolamak için, yapıları JSON'a dönüştüren ve onu documents klasöründeki bir metin dosyasına kaydeden (WWDC 2017'de tanıtılan) Codable protokolünü kullandım.

Kodu kasten çok basit tuttum. Swift ile herhangi bir deneyiminiz varsa ve görünüm denetleyicileri yapıyorsanız, bununla ilgili bir sorununuz olmamalıdır.

Artık SiriKit desteği ekleme adımlarına geçebiliriz. Üst düzey adımlar, herhangi bir uygulama ve uygulamayı planladığınız etki alanı ve amaç için aynı olacaktır. Çoğunlukla Apple'ın geliştirici web sitesiyle ilgileneceğiz, plist düzenleyeceğiz ve biraz Swift yazacağız.

List-o-Mat için, not alma uygulamaları ve yapılacaklar listeleri gibi şeylere genel olarak uygulanabilen listeler ve notlar alanına odaklanacağız.

Listeler ve notlar alanında, uygulamamız için anlamlı olabilecek aşağıdaki amaçlara sahibiz.

  • Görevlerin bir listesini alın.
  • Listeye yeni bir görev ekleyin.

Siri ile etkileşimler aslında uygulamanızın dışında gerçekleştiğinden (belki uygulamanız çalışmıyorken bile), iOS bunu uygulamak için bir uzantı kullanır.

Amaç Uzantısı

Uzantılarla çalışmadıysanız, üç ana şeyi bilmeniz gerekir:

  1. Uzatma ayrı bir işlemdir. Uygulamanızın paketi içinde teslim edilir, ancak kendi korumalı alanı ile tamamen kendi başına çalışır.
  2. Uygulamanız ve uzantınız, aynı uygulama grubunda yer alarak birbirleriyle iletişim kurabilir. En kolay yol, grubun paylaşılan sanal alan klasörleridir (böylece, onları oraya koyarsanız aynı dosyaları okuyup yazabilirler).
  3. Uzantılar kendi uygulama kimliklerini, profillerini ve yetkilendirmelerini gerektirir.

Uygulamanıza bir uzantı eklemek için geliştirici hesabınıza giriş yaparak ve "Sertifikalar, Tanımlayıcılar ve Profiller" bölümüne giderek başlayın.

Apple Geliştirici Uygulaması Hesap Verilerinizi Güncelleme

Apple geliştirici hesabımızda yapmamız gereken ilk şey bir uygulama grubu oluşturmak. "Tanımlayıcılar" altındaki "Uygulama Grupları" bölümüne gidin ve bir tane ekleyin.

Bir uygulama grubunu kaydetmek için Apple geliştirici web sitesi iletişim kutusunun ekran görüntüsü
Bir uygulama grubunu kaydetme (Geniş önizleme)

group ile başlamalı ve ardından normal ters etki alanı tabanlı tanımlayıcınız gelmelidir. Ön eki olduğundan, geri kalanı için uygulamanızın tanımlayıcısını kullanabilirsiniz.

Ardından, bu grubu kullanmak ve Siri'yi etkinleştirmek için uygulamamızın kimliğini güncellememiz gerekiyor:

  1. "Uygulama Kimlikleri" bölümüne gidin ve uygulamanızın kimliğini tıklayın;
  2. "Düzenle" düğmesini tıklayın;
  3. Uygulama gruplarını etkinleştirin (başka bir uzantı için etkinleştirilmemişse).
    Bir uygulama kimliği için uygulama gruplarını etkinleştiren Apple geliştirici web sitesinin ekran görüntüsü
    Uygulama gruplarını etkinleştir (Büyük önizleme)
  4. Ardından "Düzenle" düğmesini tıklayarak uygulama grubunu yapılandırın. Uygulama grubunu önceden seçin.
    Uygulama grubu adını ayarlamak için Apple geliştirici web sitesi iletişim kutusunun ekran görüntüsü
    Uygulama grubunun adını ayarlayın (Büyük önizleme)
  5. SiriKit'i etkinleştirin.
    SiriKit'in etkinleştirildiğinin bir ekran görüntüsü
    SiriKit'i Etkinleştir (Büyük önizleme)
  6. Kaydetmek için “Bitti”ye tıklayın.

Şimdi, uzantımız için yeni bir uygulama kimliği oluşturmamız gerekiyor:

  1. Aynı "Uygulama Kimlikleri" bölümünde yeni bir uygulama kimliği ekleyin. Bu, son ekiyle birlikte uygulamanızın tanımlayıcısı olacaktır. Son ek olarak yalnızca Intents kullanmayın çünkü bu ad Swift'de modülünüzün adı olacak ve daha sonra gerçek Intents ile çelişecektir.
    Bir uygulama kimliği oluşturmak için Apple geliştirici ekranının ekran görüntüsü
    Intents uzantısı için bir uygulama kimliği oluşturun (Geniş önizleme)
  2. Bu uygulama kimliğini uygulama grupları için de etkinleştirin (ve grubu daha önce yaptığımız gibi ayarlayın).

Şimdi, Intents uzantısı için bir geliştirme ön hazırlık profili oluşturun ve uygulamanızın ön hazırlık profilini yeniden oluşturun. Bunları normalde yaptığınız gibi indirin ve kurun.

Artık profillerimiz yüklendiğine göre, Xcode'a gitmemiz ve uygulamanın yetkilerini güncellememiz gerekiyor.

Uygulamanızın Yetkilerini Xcode'da Güncelleme

Xcode'a geri dönün, proje gezgininde projenizin adını seçin. Ardından, uygulamanızın ana hedefini seçin ve “Yetenekler” sekmesine gidin. Orada, Siri desteğini açmak için bir anahtar göreceksiniz.

SiriKit'in etkinleştirildiğini gösteren Xcode yetkilendirme ekranının ekran görüntüsü
Uygulamanızın yetkilendirmelerinde SiriKit'i etkinleştirin. (Büyük önizleme)

Listenin aşağısında, uygulama gruplarını açabilir ve yapılandırabilirsiniz.

Uygulama grubunun etkinleştirildiğini ve yapılandırıldığını gösteren Xcode yetkilendirme ekranının ekran görüntüsü
Uygulamanın uygulama grubunu yapılandırın (Büyük önizleme)

Ayarı doğru yaptıysanız, uygulamanızın .entitlements dosyasında şunu görürsünüz:

Yetkilerin ayarlandığını gösteren Uygulama listesinin bir ekran görüntüsü
Plist, belirlediğiniz yetkileri gösterir (Büyük önizleme)

Şimdi nihayet Intents extension hedefini projemize eklemeye hazırız.

Intens Uzantısını Ekleme

Sonunda uzantıyı eklemeye hazırız. Xcode'da “Dosya” → “Yeni Hedef”i seçin. Bu sayfa açılır:

Xcode'daki Yeni Hedef iletişim kutusunda Intents uzantısını gösteren bir ekran görüntüsü
Intents uzantısını projenize ekleyin (Büyük önizleme)

"Amaç Uzantısı"nı seçin ve "İleri" düğmesini tıklayın. Aşağıdaki ekranı doldurun:

Intents uzantısını nasıl yapılandırdığınızı gösteren Xcode'dan bir ekran görüntüsü
Intents uzantısını yapılandırın (Büyük önizleme)

Ürün adının, Apple geliştirici web sitesindeki amaç uygulama kimliğinde son eki yaptığınız şeyle eşleşmesi gerekir.

Bir amaç kullanıcı arayüzü uzantısı eklememeyi seçiyoruz. Bu, bu makalede ele alınmamıştır, ancak ihtiyacınız olursa daha sonra ekleyebilirsiniz. Temel olarak, Siri'nin görsel sonuçlarına kendi markanızı ve görüntü stilinizi koymanın bir yolu.

İşiniz bittiğinde, Xcode, Siri uygulamamız için başlangıç ​​parçası olarak kullanabileceğimiz bir amaç işleyici sınıfı oluşturacaktır.

Intents Handler: Çözümle, Onaylama ve İşleme

Xcode, bizim için bir başlangıç ​​noktası olan yeni bir hedef oluşturdu.

Yapmanız gereken ilk şey, bu yeni hedefi uygulama ile aynı uygulama grubunda olacak şekilde ayarlamaktır. Daha önce olduğu gibi, hedefin “Yetenekler” sekmesine gidin ve uygulama gruplarını açın ve grup adınızla yapılandırın. Aynı gruptaki uygulamaların, birbirleriyle dosya paylaşmak için kullanabilecekleri bir sanal alanı olduğunu unutmayın. Siri isteklerinin uygulamamıza ulaşması için buna ihtiyacımız var.

List-o-Mat, grup belge klasörünü döndüren bir işleve sahiptir. Paylaşılan bir dosyayı okumak veya yazmak istediğimizde kullanmalıyız.

 func documentsFolder() -> URL? { return FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.app-o-mat.ListOMat") }

Örneğin, listeleri kaydettiğimizde şunu kullanırız:

 func save(lists: Lists) { guard let docsDir = documentsFolder() else { fatalError("no docs dir") } let url = docsDir.appendingPathComponent(fileName, isDirectory: false) // Encode lists as JSON and save to url }

Intents uzantısı şablonu, IntentHandler.swift IntentHandler bir dosya oluşturdu. Ayrıca bunu, uzantının plist amaçların giriş noktası olacak şekilde yapılandırdı.

IntentHandler'ın bir giriş noktası olarak nasıl yapılandırıldığını gösteren Xcode'dan bir ekran görüntüsü
Amaç uzantısı plist, IntentHandler'ı giriş noktası olarak yapılandırır

Bu aynı plist , desteklediğimiz amaçları beyan etmek için bir bölüm göreceksiniz. INSearchForNotebookItemsIntent adlı listeleri aramaya izin verenle başlayacağız. IntentsSupported altındaki diziye ekleyin.

Xcode'da, uzantı plistinin işlediği amaçları listelemesi gerektiğini gösteren bir ekran görüntüsü
Niyetin adını niyet listesine ekleyin (Büyük önizleme)

Şimdi IntentHandler.swift gidin ve içeriğini şu kodla değiştirin:

 import Intents class IntentHandler: INExtension { override func handler(for intent: INIntent) -> Any? { switch intent { case is INSearchForNotebookItemsIntent: return SearchItemsIntentHandler() default: return nil } } }

handler işlevi, belirli bir amacı işlemek için bir nesneyi almak için çağrılır. Bu sınıftaki tüm protokolleri uygulayabilir ve self döndürebilirsiniz, ancak daha iyi organize olması için her amacı kendi sınıfına koyacağız.

Birkaç farklı sınıfa sahip olmayı amaçladığımız için, aralarında paylaşmamız gereken kod için ortak bir temel sınıf verelim:

 class ListOMatIntentsHandler: NSObject { }

Amaç çerçevesi, NSObject devralmamızı gerektirir. Bazı yöntemleri daha sonra dolduracağız.

Arama uygulamamıza şununla başlıyoruz:

 class SearchItemsIntentHandler: ListOMatIntentsHandler, INSearchForNotebookItemsIntentHandling { }

Bir amaç işleyicisi ayarlamak için üç temel adımı uygulamamız gerekir.

  1. Parametreleri çözün .
    Gerekli parametrelerin verildiğinden emin olun ve tam olarak anlamadığınız her şeyi netleştirin.
  2. İsteğin yapılabilir olduğunu onaylayın .
    Bu genellikle isteğe bağlıdır, ancak her parametrenin iyi olduğunu bilseniz bile, yine de bir dış kaynağa erişmeniz veya başka gereksinimleriniz olabilir.
  3. İsteği ele alın.
    Talep edilen şeyi yapın.

Uygulayacağımız ilk amaç olan INSearchForNotebookItemsIntent görev araması olarak kullanılabilir. Bununla başa çıkabileceğimiz istek türleri, "List-o-Mat'ta bakkal listesini göster" veya "List-o-Mat'te mağaza listesini göster" şeklindedir.

Bir yana: “List-o-Mat” aslında bir SiriKit uygulaması için kötü bir isim çünkü Siri, uygulamalarda kısa çizgilerle zor anlar yaşıyor. Neyse ki, SiriKit alternatif isimlere sahip olmamıza ve telaffuz sağlamamıza izin veriyor. Uygulamanın Info.plist şu bölümü ekleyin:

Uygulama listesinin alternatif uygulama adları ve telaffuzlar ekleyebileceğini gösteren Xcode'dan bir ekran görüntüsü
Uygulama listesine alternatif uygulama adları ve telaffuz kılavuzları ekleyin

Bu, kullanıcının “list oh mat” demesine ve bunun için tek bir kelime (tire olmadan) olarak anlaşılmasına izin verir. Ekranda ideal görünmüyor, ancak onsuz, Siri bazen “Liste” ve “Mat” ın ayrı kelimeler olduğunu düşünüyor ve çok karışıyor.

Çözüm: Parametreleri Bulma

Not defteri öğelerini aramak için birkaç parametre vardır:

  1. öğe türü (görev, görev listesi veya not),
  2. öğenin başlığı,
  3. öğenin içeriği,
  4. tamamlanma durumu (görevin tamamlandı olarak işaretlenip işaretlenmediği),
  5. ilişkili olduğu konum,
  6. ilişkili olduğu tarih.

Yalnızca ilk ikisine ihtiyacımız var, bu yüzden onlar için çözümleme işlevleri yazmamız gerekecek. INSearchForNotebookItemsIntent , uygulamamız için yöntemlere sahiptir.

Yalnızca görev listelerini göstermeyi önemsediğimiz için, bunu öğe türü çözümüne sabit kodlayacağız. SearchItemsIntentHandler içinde şunu ekleyin:

 func resolveItemType(for intent: INSearchForNotebookItemsIntent, with completion: @escaping (INNotebookItemTypeResolutionResult) -> Void) { completion(.success(with: .taskList)) }

Bu nedenle, kullanıcı ne derse desin, görev listelerini arıyor olacağız. Arama desteğimizi genişletmek isteseydik, Siri'nin bunu orijinal ifadeden çözmeye çalışmasına ve ardından öğe türü eksikse completion(.needsValue()) kullanmasına izin verirdik. Alternatif olarak, neyin uyuştuğunu görerek başlıktan tahmin etmeye çalışabiliriz. Bu durumda, Siri ne olduğunu bildiğinde başarı ile tamamlardık ve birden fazla olasılık deneyeceğimiz zaman completion(.notRequired()) kullanırdık.

Başlık çözünürlüğü biraz daha zor. İstediğimiz şey, Siri'nin söylediklerinizle tam olarak eşleşen bir liste bulursa bir liste kullanmasıdır. Emin değilse veya birden fazla olasılık varsa, o zaman Siri'nin bunu çözmek için bizden yardım istemesini isteriz. Bunu yapmak için SiriKit, daha sonra ne olmasını istediğimizi ifade etmemize izin veren bir dizi çözünürlük sıralaması sağlar.

Bu nedenle, "Bakkal" derseniz, Siri'nin tam bir eşleşmesi olur. Ancak “Mağaza” derseniz, Siri eşleşen listelerden oluşan bir menü sunar.

Temel yapıyı vermek için bu fonksiyonla başlayacağız:

 func resolveTitle(for intent: INSearchForNotebookItemsIntent, with completion: @escaping (INSpeakableStringResolutionResult) -> Void) { guard let title = intent.title else { completion(.needsValue()) return } let possibleLists = getPossibleLists(for: title) completeResolveListName(with: possibleLists, for: title, with: completion) }

ListOMatIntentsHandler temel sınıfında getPossibleLists(for:) ve completeResolveListName(with:for:with:) öğelerini uygulayacağız.

getPossibleLists(for:) , Siri'nin bize ilettiği başlıkla gerçek liste adlarını bulanık eşleştirmeye çalışmalıdır.

 public func getPossibleLists(for listName: INSpeakableString) -> [INSpeakableString] { var possibleLists = [INSpeakableString]() for l in loadLists() { if l.name.lowercased() == listName.spokenPhrase.lowercased() { return [INSpeakableString(spokenPhrase: l.name)] } if l.name.lowercased().contains(listName.spokenPhrase.lowercased()) || listName.spokenPhrase.lowercased() == "all" { possibleLists.append(INSpeakableString(spokenPhrase: l.name)) } } return possibleLists }

Tüm listelerimizi dolaşıyoruz. Tam bir eşleşme elde edersek, onu döndürürüz ve değilse, bir dizi olasılık döndürürüz. Bu fonksiyonda, kullanıcının söylediği kelimenin bir liste adında yer alıp almadığını kontrol ediyoruz (yani, oldukça basit bir eşleşme). Bu, "Bakkal"ın "Bakkal" ile eşleşmesini sağlar. Daha gelişmiş bir algoritma, kulağa aynı gelen sözcükleri temel alarak eşleştirmeyi deneyebilir (örneğin, Soundex algoritması ile),

completeResolveListName(with:for:with:) , bu olasılıklar listesiyle ne yapılacağına karar vermekten sorumludur.

 public func completeResolveListName(with possibleLists: [INSpeakableString], for listName: INSpeakableString, with completion: @escaping (INSpeakableStringResolutionResult) -> Void) { switch possibleLists.count { case 0: completion(.unsupported()) case 1: if possibleLists[0].spokenPhrase.lowercased() == listName.spokenPhrase.lowercased() { completion(.success(with: possibleLists[0])) } else { completion(.confirmationRequired(with: possibleLists[0])) } default: completion(.disambiguation(with: possibleLists)) } }

Tam bir eşleşme bulursak, Siri'ye başardığımızı söyleriz. Kesin olmayan bir eşleşmemiz varsa, Siri'ye kullanıcıya doğru tahmin edip etmediğimizi sormasını söyleriz.

Birden fazla eşleşmemiz varsa, Siri'ye bir liste göstermesini ve kullanıcının bir liste seçmesine izin vermesini söylemek için completion(.disambiguation(with: possibleLists)) kullanırız.

Artık talebin ne olduğunu bildiğimize göre, her şeye bakmamız ve halledebileceğimizden emin olmamız gerekiyor.

Onaylayın: Tüm Bağımlılıklarınızı Kontrol Edin

Bu durumda, tüm parametreleri çözdüysek, isteği her zaman işleyebiliriz. Tipik confirm() uygulamaları, harici hizmetlerin kullanılabilirliğini veya yetki düzeylerini kontrol edebilir.

confirm() isteğe bağlı olduğundan, hiçbir şey yapamayız ve Siri, herhangi bir isteği çözümlenmiş parametrelerle işleyebileceğimizi varsayar. Açık olmak gerekirse, şunu kullanabiliriz:

 func confirm(intent: INSearchForNotebookItemsIntent, completion: @escaping (INSearchForNotebookItemsIntentResponse) -> Void) { completion(INSearchForNotebookItemsIntentResponse(code: .success, userActivity: nil)) }

Bu, her şeyi halledebileceğimiz anlamına gelir.

Kolu: Yap

Son adım, talebi işleme koymaktır.

 func handle(intent: INSearchForNotebookItemsIntent, completion: @escaping (INSearchForNotebookItemsIntentResponse) -> Void) { guard let title = intent.title, let list = loadLists().filter({ $0.name.lowercased() == title.spokenPhrase.lowercased()}).first else { completion(INSearchForNotebookItemsIntentResponse(code: .failure, userActivity: nil)) return } let response = INSearchForNotebookItemsIntentResponse(code: .success, userActivity: nil) response.tasks = list.items.map { return INTask(title: INSpeakableString(spokenPhrase: $0.name), status: $0.done ? INTaskStatus.completed : INTaskStatus.notCompleted, taskType: INTaskType.notCompletable, spatialEventTrigger: nil, temporalEventTrigger: nil, createdDateComponents: nil, modifiedDateComponents: nil, identifier: "\(list.name)\t\($0.name)") } completion(response) }

İlk olarak, başlığa göre listeyi buluyoruz. Bu noktada, resolveTitle , tam bir eşleşme elde edeceğimizden emin oldu. Ancak bir sorun varsa, yine de bir başarısızlık döndürebiliriz.

Bir hatamız olduğunda, bir kullanıcı etkinliğini geçme seçeneğimiz var. Uygulamanız Handoff kullanıyorsa ve tam olarak bu tür bir istekle başa çıkmanın bir yolu varsa, Siri, isteği orada denemek için uygulamanızı ertelemeyi deneyebilir. Bunu yalnızca ses bağlamındayken yapmayacaktır (örneğin, “Hey Siri” ile başladınız) ve diğer durumlarda yapacağını garanti etmez, bu yüzden buna güvenmeyin.

Bu artık test edilmeye hazırdır. Xcode'daki hedef listesinden amaç uzantısını seçin. Ancak çalıştırmadan önce şemayı düzenleyin.

Bir şemanın nasıl düzenleneceğini gösteren Xcode'dan bir ekran görüntüsü
Hata ayıklama için örnek bir ifade eklemek amacıyla amacın şemasını düzenleyin.

Bu, doğrudan bir sorgu sağlamanın bir yolunu getirir:

Düzenleme şeması iletişim kutusunu gösteren Xcode'dan bir ekran görüntüsü
Örnek ifadeyi şemanın Çalıştır bölümüne ekleyin. (Büyük önizleme)

Dikkat, yukarıda bahsedilen tire sorunu nedeniyle “ListOMat” kullanıyorum. Neyse ki, uygulamamın adıyla aynı şekilde telaffuz ediliyor, bu yüzden çok fazla sorun olmamalı.

Uygulamaya geri döndüğümde bir “Bakkal” listesi ve bir “Donanım Mağazası” listesi yaptım. Siri'den "mağaza" listesini istersem, şuna benzeyen anlam ayrımı yolundan geçer:

Siri'nin Mağaza listesini gösterme isteğini ele aldığını gösteren animasyonlu bir GIF
Siri, açıklama isteyerek isteği yerine getirir. (Büyük önizleme)

“Bakkal” derseniz, doğrudan sonuçlara giden tam bir eşleşme elde edersiniz.

Siri Üzerinden Öğe Ekleme

Artık çözümleme, onaylama ve işleme temel kavramlarını bildiğimize göre, listeye bir öğe ekleme niyetini hızla ekleyebiliriz.

İlk olarak, uzantının INAddTasksIntent ekleyin:

Plist'e eklenen yeni amacı gösteren XCode'da bir ekran görüntüsü
Uzantı listesine INAddTasksIntent'i ekleyin (Büyük önizleme)

Ardından, IntentHandler handle işlevimizi güncelleyin.

 override func handler(for intent: INIntent) -> Any? { switch intent { case is INSearchForNotebookItemsIntent: return SearchItemsIntentHandler() case is INAddTasksIntent: return AddItemsIntentHandler() default: return nil } }

Yeni sınıf için bir saplama ekleyin:

 class AddItemsIntentHandler: ListOMatIntentsHandler, INAddTasksIntentHandling { }

Bir öğe eklemek, başlık yerine hedef görev listesi dışında, arama için benzer bir resolve gerektirir.

 func resolveTargetTaskList(for intent: INAddTasksIntent, with completion: @escaping (INTaskListResolutionResult) -> Void) { guard let title = intent.targetTaskList?.title else { completion(.needsValue()) return } let possibleLists = getPossibleLists(for: title) completeResolveTaskList(with: possibleLists, for: title, with: completion) }

completeResolveTaskList , completeResolveListName gibidir, ancak biraz farklı türlere sahiptir (görev listesinin başlığı yerine bir görev listesi).

 public func completeResolveTaskList(with possibleLists: [INSpeakableString], for listName: INSpeakableString, with completion: @escaping (INTaskListResolutionResult) -> Void) { let taskLists = possibleLists.map { return INTaskList(title: $0, tasks: [], groupName: nil, createdDateComponents: nil, modifiedDateComponents: nil, identifier: nil) } switch possibleLists.count { case 0: completion(.unsupported()) case 1: if possibleLists[0].spokenPhrase.lowercased() == listName.spokenPhrase.lowercased() { completion(.success(with: taskLists[0])) } else { completion(.confirmationRequired(with: taskLists[0])) } default: completion(.disambiguation(with: taskLists)) } }

Aynı belirsizlik giderme mantığına sahiptir ve tamamen aynı şekilde davranır. "Mağaza" kelimesinin anlamı netleştirilmeli ve "Bakkal" demek tam bir eşleşme olacaktır.

confirm uygulamadan bırakacağız ve varsayılanı kabul edeceğiz. handle için listeye bir öğe eklememiz ve kaydetmemiz gerekiyor.

 func handle(intent: INAddTasksIntent, completion: @escaping (INAddTasksIntentResponse) -> Void) { var lists = loadLists() guard let taskList = intent.targetTaskList, let listIndex = lists.index(where: { $0.name.lowercased() == taskList.title.spokenPhrase.lowercased() }), let itemNames = intent.taskTitles, itemNames.count > 0 else { completion(INAddTasksIntentResponse(code: .failure, userActivity: nil)) return } // Get the list var list = lists[listIndex] // Add the items var addedTasks = [INTask]() for item in itemNames { list.addItem(name: item.spokenPhrase, at: list.items.count) addedTasks.append(INTask(title: item, status: .notCompleted, taskType: .notCompletable, spatialEventTrigger: nil, temporalEventTrigger: nil, createdDateComponents: nil, modifiedDateComponents: nil, identifier: nil)) } // Save the new list lists[listIndex] = list save(lists: lists) // Respond with the added items let response = INAddTasksIntentResponse(code: .success, userActivity: nil) response.addedTasks = addedTasks completion(response) }

Bir öğe listesi ve bir hedef listesi alıyoruz. Listeye bakıp öğeleri ekliyoruz. Ayrıca Siri'nin eklenen öğelerle birlikte göstermesi ve tamamlama işlevine göndermesi için bir yanıt hazırlamamız gerekiyor.

Bu işlev, “ListOMat'ta alışveriş listesine elma ekleyin” gibi bir ifadeyi işleyebilir. Ayrıca "pirinç, soğan ve zeytin" gibi öğelerin bir listesini de işleyebilir.

Siri'nin market listesine ürün eklediğini gösteren simülatörün ekran görüntüsü
Siri, market listesine birkaç öğe ekler

Neredeyse Tamamlandı, Sadece Birkaç Ayar Daha

Bunların tümü simülatörünüzde veya yerel cihazınızda çalışır, ancak bunu göndermek istiyorsanız, uygulamanızın plist Siri'yi ne için kullandığınızı açıklayan bir dizeyle bir NSSiriUsageDescription anahtarı eklemeniz gerekir. “Listelerle ilgili istekleriniz Siri'ye gönderilecek” gibi bir şey sorun değil.

Ayrıca bir arama eklemelisiniz:

 INPreferences.requestSiriAuthorization { (status) in }

Kullanıcıdan Siri erişimi istemek için bunu ana görünüm denetleyicinizin viewDidLoad koyun. This will show the message you configured above and also let the user know that they could be using Siri for this app.

A screenshot of the dialog that a device pops up when you ask for Siri permission
The device will ask for permission if you try to use Siri in the app.

Finally, you'll need to tell Siri what to tell the user if the user asks what your app can do, by providing some sample phrases:

  1. Create a plist file in your app (not the extension), named AppIntentVocabulary.plist .
  2. Fill out the intents and phrases that you support.
A screenshot of the AppIntentVocabulary.plist showing sample phrases
Add an AppIntentVocabulary.plist to list the sample phrases that will invoke the intent you handle. (Büyük önizleme)

There is no way to really know all of the phrases that Siri will use for an intent, but Apple does provide a few samples for each intent in its documentation. The sample phrases for task-list searching show us that Siri can understand “Show me all my notes on <appName>,” but I found other phrases by trial and error (for example, Siri understands what “lists” are too, not just notes).

Özet

As you can see, adding Siri support to an app has a lot of steps, with a lot of configuration. But the code needed to handle the requests was fairly simple.

There are a lot of steps, but each one is small, and you might be familiar with a few of them if you have used extensions before.

Here is what you'll need to prepare for a new extension on Apple's developer website:

  1. Make an app ID for an Intents extension.
  2. Make an app group if you don't already have one.
  3. Use the app group in the app ID for the app and extension.
  4. Add Siri support to the app's ID.
  5. Regenerate the profiles and download them.

And here are the steps in Xcode for creating Siri's Intents extension:

  1. Add an Intents extension using the Xcode template.
  2. Update the entitlements of the app and extension to match the profiles (groups and Siri support).
  3. Add your intents to the extension's plist .

And you'll need to add code to do the following things:

  1. Use the app group sandbox to communicate between the app and extension.
  2. Add classes to support each intent with resolve, confirm and handle functions.
  3. Update the generated IntentHandler to use those classes.
  4. Ask for Siri access somewhere in your app.

Finally, there are some Siri-specific configuration settings:

  1. Add the Siri support security string to your app's plist .
  2. Add sample phrases to an AppIntentVocabulary.plist file in your app.
  3. Run the intent target to test; edit the scheme to provide the phrase.

OK, that is a lot, but if your app fits one of Siri's domains, then users will expect that they can interact with it via voice. And because the competition for voice assistants is so good, we can only expect that WWDC 2018 will bring a bunch more domains and, hopefully, much better Siri.

Daha fazla okuma

  • “SiriKit,” Apple
    The technical documentation contains the full list of domains and intents.
  • “Guides and Sample Code,” Apple
    Includes code for many domains.
  • “Introducing SiriKit” (video, Safari only), WWDC 2016 Apple
  • “What's New in SiriKit” (video, Safari only), WWDC 2017, Apple
    Apple introduces lists and notes
  • “Lists and Notes,” Apple
    The full list of lists and notes intents.