[Swift] 44 Apple WatchのComplication改良 / watchOS 10による表示不良 解決 / containerBackground

[Mac M2 Pro 12CPU, Ventura 13.6, watchOS 10.0.1, Xcode 15.0]

[Swift] 42で報告したComplicationの表示不良が解決しました。Viewコンテンツの新属性として.containerBackgroundを追加するだけでした。

watchOSの大型アップデートの際に新属性記述が必須になることがあるようです。Apple Developer ForumsとMac OTAKARAの記事を参考に修正しました。

WWDC23で前もって紹介されており、Appleのやらかしではありませんでした。

ただApple Watch SEのシミュレータでは新属性なしでも正常表示しているのが解せないです。アップデートしたwatchOS 10では対応が必要で、watchOS 10そのものには不要なのでしょうか。

解決しない場合は、検証用追加機としてApple Watch Series 8あたりを購入しようかと覚悟していたので助かりました。

SE 第2世代でもいいから追加機導入して2台開発体制にする方がいいかな。iOSとは違ってwatchOSアップデートはサブ機でお試しが無難ですから。

watchOS 10でも正常表示になった
struct MemoToolAW_ComplicationsEntryView : View {
    var entry: Provider.Entry

    var body: some View {
        Image(systemName: "square.and.pencil")
        .resizable()
        .aspectRatio(contentMode: .fit)
        .foregroundColor(.white)
        .background(Color.blue)
        .containerBackground(for: .widget){  // watchOS 10から必須
            Color.blue
        }
    }
}

参考
Apple Developer Forums
Mac OTAKARA

[Swift] 43 Apple WatchのComplication改良 / accessoryCornerの円弧状表示 / watchOS 10

[Mac M2 Pro 12CPU, Ventura 13.6, watchOS 10.0.1, Xcode 15.0]

watchOS 10でComplicationのコーナー全体を円弧状表示できるようになりました。

これまではラベルのみ円弧状表示で本体は水平表示でした。水平表示では”令5″の2文字でスペース的に限界だったのを”令和5″の3文字に増やすことができました。

ただし前回記事に書いている通り、実機(Apple Watch SE)ではまともに表示できていません。シミュレータでのみ成功しています。

struct ComplicationCorner : View {
    var entry: Provider.Entry
    
    var body: some View {
        Text(getFormattedYear())
        .font(.system(size: 22))
        .widgetCurvesContent()  // これを追記、"令和5"が円弧状に表示される
        .foregroundColor(.green)
        .widgetLabel {
            Text(getFormattedDate() + getFormattedWeekday())
            .foregroundColor(.yellow)
        }
     }

[Swift] 42 Apple WatchのComplication改良 / watchOS 10による表示不良

[Mac M2 Pro 12CPU, Ventura 13.6, watchOS 10.0.1, Xcode 15.0]

watchOS 10になってAppleさん早速やらかしています。

自製のComplicationがまともに表示されなくなりました。

watchOSはAppleや専門業者以外ダウングレードできないので、Appleがバグ修正するまで放置するしかありません。

XcodeはApple Watch実機をなかなか認識できなくてビルドがままならず、watchOSアプリの開発は時間が掛かるばかりです。結局、iPhoneをMacに有線で再接続するとXcode上でApple Watch実機を認識できました。

iPhone & Apple Watchは家族のヘルスケア管理端末にして、普段使いはPixel & Pixel Watchにしようかと思い始めています。ファミリーウォッチ機能がなければとっくに見切りを付けているところです。

Complicationの
表示不良(内側上・左, 右下)

[Swift] 41 メモアプリ製作 その12 ToolbarItemのplacement新機能 watchOS 10

[Mac M2 Pro 12CPU, Ventura 13.6, watchOS 10.0.1, Xcode 15.0]

watchOSが10にバージョンアップし、watchOS版アプリのToolbarItemの位置をbottomに設定できるようになりました(.bottomBarと記述)。

これまでは”.automatic”にして上部にしか配置できませんでした。これでメモアプリwatchOS版のUIを改善できました。

この種の機能がバージョン10にしてようやく導入というのは結構遅いと思います。急ピッチで機能の拡充をお願いしたいものです。

import SwiftUI
import CoreData

struct ContentView: View {
    @Environment(\.managedObjectContext)var viewContext

    @FetchRequest(
    entity: Note.entity(),
    sortDescriptors: [NSSortDescriptor(key: "creationDate", ascending: false)])
    private var contents: FetchedResults<Note>

    var body: some View {
        NavigationView{
            List{
                ForEach(contents){content in
                    NavigationLink{
                        if((content.content?.isEmpty) == false){
                            DraftAppleWatch(text:content.content!, note: content)
                        }
                    }label:{
                        if((content.content?.isEmpty) == false){
                            Text(content.content!)
                        }
                    }
                }
                .onDelete(perform:deleteContent)
            }
            .navigationTitle("メモリスト")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar{
                ToolbarItem(placement:.bottomBar){ // ここを変更
                     NavigationLink{
                        DraftAppleWatch()
                    }label:{
                        Text("+")
                        .font(.system(size: 24))
                        

                    }
                }
            }
        }
        .accentColor(.blue)
    }
<以下略>

[Swift] 40 ChatGPTアプリ製作 その4 Apple Watchで使用

[M1 Mac, Ventura 13.3.1, Xcode 14.3]

Apple WatchでもChatGPTを使えるようにしました。一問一答形式です。

ただしiCloudにデータを上手く保存できず、それぞれのデバイスのローカルに保存されます。

CoreData: error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate recoverFromError:](2224): <NSCloudKitMirroringDelegate: 0x600003d780e0> - Attempting recovery from error: <CKError 0x600000a14630: 
"Partial Failure" (2/1011); "Failed to modify some record zones"; 
"Server Rejected Request"

[Swift] 39 Apple WatchのComplication改良 複数のComplication作成

[M1 Mac, Ventura 13.3.1, Xcode 14.3]

自製カレンダーアプリのComplicationを純正アプリと同様にラベル有りとラベル無しの2種類作成しました。

TargetとしてWidget Extensionを増やすだけなので特に問題なくできますが、作成時に”Include Configuration Intent”にチェックを入れないようにします。チェックを入れるとそのままではコマンドの重複が発生しビルドエラーになります。

Complication選択画面
@main
struct DateToolComplicationLabel: Widget {
    let kind: String = "DateToolComplicationLabel"

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            DateToolComplicationLabelEntryView(entry: entry)
        }
        .configurationDisplayName("Date ラベル付き")
        .description("")
        .supportedFamilies([.accessoryCircular,.accessoryCorner,.accessoryRectangular,.accessoryInline])
     }

}

[Swift] 38 メモアプリ製作 その11 Apple Watchで新規メモ作成

[M1 Mac, Ventura 13.3.1, Xcode 14.3]

メモアプリのwatchOS版では既存のメモを編集できるだけでした。さらに新規メモを作成できるようにしました。TextFieldなので1行の文字列として入力することになります。

後でiPhoneなどで改行を入れ整形する必要がありますが、とりあえずメモしたい時に便利です。

ToolbarItemのplacementを.automaticにして正常に配置できました。本当はプラスボタンをbottomに置きたいのですが、watchOS 9では不可のようです。watchOS 10で新機能として追加されるという情報を目にしました。本当だとしたらありがたいです。

これで大体完成と言ったところでしょうか。

struct ContentView: View {
    @Environment(\.managedObjectContext)var viewContext

    @FetchRequest(
    entity: Note.entity(),
    sortDescriptors: [NSSortDescriptor(key: "creationDate", ascending: false)])
    private var contents: FetchedResults<Note>

    var body: some View {
        NavigationView{
            List{
                ForEach(contents){content in
                    NavigationLink{
                        if((content.content?.isEmpty) == false){
                            DraftAppleWatch(text:content.content!, note: content)
                        }
                    }label:{
                        if((content.content?.isEmpty) == false){
                            Text(content.content!)
                        }
                    }
                }
                .onDelete(perform:deleteContent)
            }
            .navigationTitle("メモリスト")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar{
                ToolbarItem(placement:.automatic){
                    NavigationLink{
                        DraftAppleWatch()
                    }label:{
                        Text("+")
                        .font(.system(size: 24))
                    }
                }
            }
        }
        .accentColor(.blue)
    }
<以下略>

[Swift] 37 Apple WatchのComplication改良 しばらく経つと消える 原因判明

[M1 Mac, Ventura 13.3.1, Xcode 14.3]

自製カレンダーアプリのComplicationがしばらく経ってアプリごと消えてしまう原因が判明しました。

どうやらXcodeのバグのようです。

iOSのWatchアプリを開いて”APPLE WATCH上にインストール済み”が表示された瞬間にそこからカレンダーアプリが消えていくのを目撃しました。再現性も確認しています。

この画面になった瞬間にアプリが消えていった

アプリそのものに関する設定に問題があるのではと考え、調べていくとBundle Identiferが不完全な表記になっているのが分かりました。これはwatchOSアプリのプロジェクト作成時に正しく設定しても反映されていないことを意味します。

最初にiOSアプリのプロジェクトを作成し、watchOSアプリ、Widget Extensionと順にターゲットを増やしていくとこのような問題は起こりません。メモアプリはこの手順だったためトラブルにはなりませんでした。

さすがにこれは酷すぎるのでAppleにバグ報告します。

正直こんなことで振り回されたくない。Flutterでこの種の不毛な作業をせずに済むのであれば本気で移行したいです。

アプリのカテゴリーは異なりますが、VSCodeでこのような不具合はあり得ないです。Xcodeへの信頼を著しく損なう事になり残念至極。

プロジェクト作成時はBundle Identiferに特に問題はない
後でBundle Identiferを確認すると.watchkitappに勝手に変わっている
これでは固有IDとして機能しない

[Swift] 36 Apple WatchのComplication改良 しばらく経つと消える

[M1 Mac, Ventura 13.3.1, Xcode 14.3]

カレンダーアプリのComplicationがしばらく経つとアプリごと消えてしまいます。同様にComplication設定しているメモアプリは無事です。

“インフォグラフ”文字盤の中央上部は純正カレンダー以外のアプリを受け付けないのかもしれません。

中央上部は純正カレンダー、右下は自製カレンダーに設定して様子を見ます。

これで消えたら以下の対策を順次試してみます。
1.プロジェクトから作り直し
2.CloudKitを導入しDateなどを適当に保存
3.文字盤を作成
4.正式にアプリ登録する(非公開)

中央上部と右下に設定
しばらくすると消える
(経過時間は不定)
この設定で様子を見る
struct ComplicationCircular : View {
    @Environment(\.showsWidgetLabel) var showsWidgetLabel
    var entry: Provider.Entry
    
    var body: some View {
        VStack (spacing: -6){
            if showsWidgetLabel {
                Text(getWeekday(entry.date))
                .font(.system(size: 18))
                .foregroundColor(.yellow)
                .widgetLabel {
                    Text(getFormattedDate() + getFormattedWeekday() + getFormattedYear())
                    .foregroundColor(.blue) // 中央上部は色設定不可
                }
                
                Text(getMonth(entry.date))
                .font(.system(size: 18))
                .foregroundColor(.green)
                
                Text(getDay(entry.date))
                .font(.system(size: 18))
                .foregroundColor(.white)
                
            } else {
                Text(getWeekday(entry.date))
                .font(.system(size: 18))
                .foregroundColor(.yellow)
                
                Text(getMonth(entry.date))
                .font(.system(size: 18))
                .foregroundColor(.green)
                
                Text(getDay(entry.date))
                .font(.system(size: 18))
                .foregroundColor(.white)
            }
        }
    }
<以下略>

[Swift] 35 Apple WatchのComplication改良 accessoryCorner

[M1 Mac, Ventura 13.3.1, Xcode 14.3]

ComplicationのaccessoryCornerにも日付を表示できるようにしました。

ただし現時点では文字盤に沿って円弧状に表示できるのはラベル[23/07/08(土)]だけで本体[令5]は水平のままです。

詳しくは書けませんが、次期watchOSで何らかの進化があるようです。

中央上部と右下に表示
struct ComplicationCorner : View {
    var entry: Provider.Entry
    
    var body: some View {
        Text(getFormattedYear())
        .font(.system(size: 22))
            .foregroundColor(.green)
            .widgetLabel {
                Text(getFormattedDate() + getFormattedWeekday())
                .foregroundColor(.yellow)
            }
     }
    
    func getFormattedDate() -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yy/MM/dd"
        return dateFormatter.string(from: entry.date)
    }
    
    func getFormattedWeekday() -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "E"
        dateFormatter.locale = Locale(identifier: "ja_JP")
        return "(" + dateFormatter.string(from: entry.date) + ")"
    }
    
    func getFormattedYear() -> String {
        let calendar = Calendar(identifier: .japanese)
        let year = calendar.component(.year, from: entry.date)
        return "令" + String(year)
    }
    
}

struct DateToolComplicationEntryView : View {
    @Environment(\.widgetFamily) var widgetFamily
    var entry: Provider.Entry
    
    var body: some View {
        switch widgetFamily {
            case .accessoryCorner:
                ComplicationCorner(entry: entry)
            case .accessoryCircular:
                ComplicationCircular(entry: entry)
            case .accessoryInline:
                ComplicationInline()
            case .accessoryRectangular:
                ComplicationRectangular()
            @unknown default:
                Text("Not an implemented widget yet")
        }
    }
}