ikeh1024のブログ

ZennやQiitaに書くにはちょっと小粒なネタをこちらに書いています

LaunchDaemonsのplistファイルはroot権限でないと動作しない

  • ログイン時にアプリに起動させるために/Library/LaunchDaemons以下に.plistを配置することがある
  • このplist内のパラメータを変更しようとした際に、書き込み権限の都合上、別の場所に移して編集してそれを戻すことをした際に、plistが機能しなくなってしまった。
  • これはplistのOwnerが変わってしまったためで、root権限である必要があるとのこと
# 編集前
LaunchDaemons % ls -l@
-rw-r--r--  1 root  wheel  985 1224 17:35 xxx.Service.plist

# 編集後
LaunchDaemons % ls -l@
-rw-r--r--@ 1 <user>  wheel  1032  123 09:31 xxx.Service.plist
    com.apple.lastuseddate#PS     16 
    com.apple.metadata:kMDLabel_mymlunohiynfcncabiqhirhatm   121 
    com.apple.xcode.PlistType      0

macos - Why am I getting a "dubious ownership of file" error when Launch Agent runs my .plist file? - Ask Different ユーザーごとの設定ファイル(LaunchAgents)は、それをロードするユーザーの所有者である必要があります。システム全体のデーモン(LaunchDaemons)はすべて、rootの所有者である必要があります。設定ファイルは、グループまたはワールドレベルの書き込み権限を持つべきではありません。これらの制限はセキュリティ上の理由から設けられています。launchd設定ファイルへの書き込み権限を与えると、どの実行ファイルが起動されるかを指定できるようになるためです。

# viで編集する
sudo vi xxx.plist

# コマンドで権限をrootに戻す
sudo chown root:wheel /Library/LaunchDaemons/myfile.plist

macOS15/UTMにおいてUS配列からJIS配列にキーボードの認識を変更する

  • UTM/macOS15の仮装環境で、元のMacがJIS配列のキーボードだが仮想環境内でUS配列として認識されてしまう問題
  • 検索するとkarabiner-elementsがいいらしい

karabiner-elements.pqrs.org

  • アプリをインストールし指示通り各種権限を許可した後、下記でJISを選択

image

  • ただKarebiner-elementsのログで下記エラーがでる
[2025-06-02 15:15:51.629] [error] [console_user_server] grabber_client connect_failed: Connection refused

image

image

  • 仮想環境の今のキーボードの状態は下記から確認できる

image

  • 尚エラーを解消する中でbrew経由で再インストールしている。これによって改善したわけではないと思うが念のための記録として。

github.com

Xcodeでマルチモジュール構成を試す

参考

手順

  • 新規プロジェクトの作成

  • File > New > Package...からパッケージ(各モジュール)を作成

  • 今回Coreというパッケージを作成
  • Add to:の設定を行い、プロジェクトにパッケージを追加させる

  • プロジェクト設定から先程作成したCoreのライブラリを追加

  • 以上でアプリ本体からCoreライブラリを呼べることが確認できる

  • (参考) モジュールのPackage.swift
// swift-tools-version: 6.1
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "GitHubAPIClient",
    platforms: [
        .iOS(.v16),
        .macOS(.v10_15),
    ],
    products: [
        .library(
            name: "GitHubAPIClient",
            targets: ["GitHubAPIClient"]),
    ],
    dependencies: [
        // インポートするライブラリの指定
        .package(path: "../GitHubRESTAPI"),
        .package(path: "../GitHubAPIQraphQL"),
        .package(url: "https://github.com/pointfreeco/swift-dependencies", from: "1.0.0"),
        .package(url: "https://github.com/kishikawakatsumi/KeychainAccess", from: "4.0.0"),
    ],
    targets: [
        // ターゲットごとに利用するライブラリの指定
        .target(
            name: "GitHubAPIClient",
            dependencies: [
                "GitHubRESTAPI",
                "GitHubAPIQraphQL",
                .product(name: "Dependencies", package: "swift-dependencies"),
                .product(name: "DependenciesMacros", package: "swift-dependencies"),
                .product(name: "KeychainAccess", package: "KeychainAccess"),
            ],
            swiftSettings: [
                // マクロを使うなら `macros` セクションを追加する必要がある
                .enableUpcomingFeature("Macros"),
                .enableExperimentalFeature("StrictConcurrency")
            ],
        ),
        .testTarget(
            name: "GitHubAPIClientTests",
            dependencies: ["GitHubAPIClient"]
        ),
    ]
)

macOSでSentryのバイナリがx86_64となりユニバーサルバイナリにならない問題

  • macOSアプリでSentryを利用しているが、アプリに含まれるSentryのバイナリがx86_64だけでユニバーサルバイナリとならない問題がでた
  • 解決方法としては、静的ライブラリではなく、動的ライブラリの方を選択するといいとのこと

github.com

  • SentryではなくSentry-Dynamicのほうを選択

image

  • (ドキュメントには軽くしか書かれていない)

https://docs.sentry.io/platforms/apple/install/swift-package-manager/

Sentry is the static framework, which is the recommended option if you prefer a fast app start time.

Sentry-Dynamic is the dynamic framework.

SentrySwiftUI is used to track performance of SwiftUI views, see more information in the docs.

  • アプリ内の下記ファイルに対してlipoをすることでアーキテクチャを確認できる

image

lipo -info Sentry.framework/Sentry
Architectures in the fat file: Sentry.framework/Sentry are: x86_64 arm64 arm64e

SiriやWi-Fiのメニューバーアイコンファイルを参照する方法

  • メニューバーアイコンのデザインについて考えている。ベースは以下。
  • そこで参考としてSiriのメニューバーに表示されているアイコンのファイルを見てみたいと思ったので検索
  • 下記にあるらしい

Where are Siri menu bar icon files located? /System/Library/CoreServices/Siri.bundle/Contents/Resources/Assets.car

image

image

macOS Big Sur Wi-Fi icons location /System/Library/PrivateFrameworks/CoreWLANKit.framework/Versions/A/Resources/Assets.car

  • サイズが20/40ptで違うかも…?名称も拡張子が.pdfだし…

image

  • と思ったらPDFファイルはアイコンとして使えるらしい

Designing macOS menu bar extras Menu bar extra image assets can be a single SVG, a single PDF, or a pair of PNGs (1× and 2× scales for non-Retina and Retina displays). They can also be drawn with code, if you require something dynamic, like an analogue clock or a calendar icon that shows the day of the month.

  • アイコンのサイズって自動的にいい感じにリサイズするんだったっけ…多分そのままだったような記憶だけど曖昧なのでまた時間があるときに試す

redefinition of module 'XXX'のエラー解消

  • SwiftPMでredefinition of module 'XXX'とエラーが出た
  • XcodeClean Build FolderReset Package Cachesでも改善せず

Redefinition of module issue

Go to Project root > BuildTools > .build > arm64-apple-macosx > release Delete ArgumentParser-tool.build and ArgumentParserToolInfo-tool.build Re-build the project

  • 上記を参考に、私の場合は上記だけだと依然としてエラーだったので、.buildディレクトリを丸々削除することで解決した。

R.swiftの導入メモ

概要

image

image

エラーハンドリング

  • またUIテスト側でR.swiftを利用しようとするとエラーが出た。stringシンボルが見つからないということで、Localizable.stringsのTargetにをテスト側を追加すると解消した。
Value of type '_R' has no member 'string'

image

XcodeでInfo.plistの場所を変更する

  • Info.plistを下記のように別フォルダに移したい

image

  • 単に移してビルドするとplistが見つからないというエラーがでるので、下記のInfo.plist Fileのパスを更新すればOK

image

  • また下記の重複しているとのエラーが出たのでCopy Bundle ResourcesInfo.plistがある場合はそれを消すと良い
Prepare build
error: Multiple commands produce '/Users/ikeh/Library/Developer/Xcode/DerivedData/iOSEngineerCodeCheck-baojqjmcmqcbrrghemetsfapulot/Build/Products/Debug-iphonesimulator/iOSEngineerCodeCheck.app/Info.plist'
    note: Target 'iOSEngineerCodeCheck' (project 'iOSEngineerCodeCheck') has copy command from '/Users/ikeh/github-repository-search/iOSEngineerCodeCheck/Resources/Info.plist' to '/Users/ikeh/Library/Developer/Xcode/DerivedData/iOSEngineerCodeCheck-baojqjmcmqcbrrghemetsfapulot/Build/Products/Debug-iphonesimulator/iOSEngineerCodeCheck.app/Info.plist'
    note: Target 'iOSEngineerCodeCheck' (project 'iOSEngineerCodeCheck') has process command with output '/Users/ikeh/Library/Developer/Xcode/DerivedData/iOSEngineerCodeCheck-baojqjmcmqcbrrghemetsfapulot/Build/Products/Debug-iphonesimulator/iOSEngineerCodeCheck.app/Info.plist'


Multiple commands produce '/Users/ikeh/Library/Developer/Xcode/DerivedData/iOSEngineerCodeCheck-baojqjmcmqcbrrghemetsfapulot/Build/Products/Debug-iphonesimulator/iOSEngineerCodeCheck.app/Info.plist'

image

古いnibファイルをXcodeで読み込む際にエラーになった際の対処方法

  • かなり古いnibをXcodeで読み込もうとすると、下記のエラーが出て表示することすらできない問題にあたった。
Tried to create a document (class: IBXIBDocument) and got a document with a different, non-conforming fileType back instead.
ibtool LicenseInfo.nib --upgrade --write new/LicenseInfo.xib

SwiftPMの管理方法に、XcodeかPackage.swiftのどちらを採用するか

前提

  • SwiftPMの管理方法には2種類ある
    • Xcode上で管理する方法
    • Package.swiftで管理する方法
  • 特に理由がなければ基本的にXcode上で管理する方法を推奨

Package.swiftのユースケースと考慮する点

ユースケース

  • 基本的に外部公開用パッケージ・マルチモジュール構成のときに利用される
  • またDependabotやRenovateなどのライブラリのアップデートがあった際に、自動でPRをつくってくれるツールがあるが、この際にPackage.swiftを利用している必要がある
  • Xcodeの対応はIssuesにもあがっているが難しいみたい

https://team-blog.mitene.us/upgrade-swiftpm-library-renovate-71f7e8489775 Renovateのドキュメントに記載がある通り、 Package.swift 内のライブラリには対応していますが、Xcodeプロジェクトから入れたライブラリには対応していません。

考慮する点

  • Package.swiftはXcodeに付随している依存関係解決ツールのバージョンまで指定しているので、Xcodeのバージョンアップをしたりすると動かなくなることがある
  • 外部ライブラリにリソースを割くのが勿体ない

Xcode上で管理する方法」の場合のライブラリのアップデート方針

  • Renovateなどが利用できないので、ライブラリをアップデートするための方針を考える
  • 例えば以下の例がある

97:バージョンをいつ上げるのか

DjangoCeleryといった機能や影響が大きいフレームワークの場合、パッチバージョン(2.2.8→2.2.9) [1] の適用はこまめに行いましょう。

フレームワーク以外のライブラリ 1年に1回など、定期的にバージョンを更新していくのが良いでしょう。

開発用のツール flake8、mypy、pytest、toxといった開発中だけ使用するライブラリは、極端なことを言えばバージョンを上げる必要はありません。 半年以上継続する開発プロジェクトであれば、他のライブラリの更新時に合わせてバージョンアップする戦略が良いでしょう。

  • またはあるiOSエンジニアの方に聞いた方針は以下の通り
  • まずはライブラリのバージョンのルールを指定する
  • 破壊的な変更があり得るかどうかで分けるといい
    • Realmやアーキテクチャ系のライブラリなどの主要なライブラリは固定バージョン
    • その他のライブラリは常に最新のMajorバージョンになるように指定
  • 前者に関してライブラリの更新情報は随時キャッチアップしておき、影響がないかをチェックしたり、アップデートを検討する
    • キャッチアップする工夫として、GASで検知してSlackのチャンネルに投稿したり、iOS Osushiを利用すると良い

@AppStorage用のキーとreset関数を提供するSwift Macrosの作成

概要

  • Swift Macrosの習作として下記を作成するMacroを作成してみました。
    • @AppStorageに渡すKey
    • デフォルト値に戻すためのreset関数
  • https://github.com/pommdau/userdefaults-key-macro
    • (まだまだ理解が浅いので型推論の場合に未対応などいくつか問題は残っている)

モチベーション

  • 開発しているアプリで下記のようなコードがあって、泥臭い実装でなんだかなーと思って棚上げしていた箇所を、Swift Macrosで解決できるのではと考えた
  • 問題としては…
  • 文字列指定をさけるためのenum Propertyの宣言が面倒
  • 初期値を定義するためのdefaultParameterとかもあまり良くない書き方そう
extension RopeSettings {
        
    enum Property: String, CaseIterable {
        case needsShadow
        case ropeWidth
        case ropeOpacity
        case elasticity
        
        // e.g. "GeneralSettings-shapeSize"
        var key: String {
            "\(className)-\(rawValue)"
        }
        
        func defaultParameter<T>() -> T {                        
            switch self {
            case .needsShadow:
                return true as! T
            case .ropeWidth:
                return 6.0 as! T
            case .ropeOpacity:
                return 1.0 as! T
            case .elasticity:
                return Elasticity.elastic as! T
            }
        }
    }
    
    private static var className: String {
        String(describing: self)
    }
}

extension RopeSettings {
    static func resetUserDefaults() {
        Property.allCases.forEach { userDefaultsKey in
            UserDefaults.standard.removeObject(forKey: userDefaultsKey.key)
        }
    }    
}
import SwiftUI

class RopeSettings: ObservableObject {
    
    static let shared = RopeSettings()
    let settingsPaneType: SettingsPaneType = .rope
    
    // MARK: - User Settings
                                   
    @AppStorage(Property.needsShadow.key)
    var needsShadow: Bool = Property.needsShadow.defaultParameter()
    
    @AppStorage(Property.ropeWidth.key)
    var ropeWidth: Double = Property.ropeWidth.defaultParameter()
    
    @AppStorage(Property.ropeOpacity.key)
    var ropeOpacity: Double = Property.ropeOpacity.defaultParameter()
    
    @AppStorage(Property.elasticity.key)
    var elasticity: Elasticity = Property.elasticity.defaultParameter()
     
    init() {
//        Self.resetUserDefaults()
    }
}

PyAutoGUIのlocateCenterOnScreenは例外を投げるという話

概要

  • サンプルコードでlocateCenterOnScreenの返り値がNoneかどうかを判断するものがあるが、現状は例外エラーが投げられる。

  • plaza.rakuten.co.jp

  • www.fixes.pub

  • このようにエラーハンドリングをする
import pyautogui
# force use of ImageNotFoundException
pyautogui.useImageNotFoundException()
try:
    location= pyautogui.locateOnScreen('foo.png')
    print('image found')
except pyautogui.ImageNotFoundException:
    print('ImageNotFoundException: image not found')
  • これはちょっと認識違いかも?(pyscreezeではなくpuautogui側のImageNotFoundExceptionを使うべき)

teratail.com

pyautogui の内部で使われている pyscreeze が2度仕様変更しましたが、pyautogui が2度目の仕様変更に追従していないようです。

PC内のフォントファイルのURLを全取得する

  • 前提としてSandBoxをOFFにしておくこと
struct URLManager {
    
    /// 検索対象となるFontsディレクトリ
    static private var fontsDirectories: [URL] {
        guard
            let directoryInSystem = FileManager.default.urls(for: .libraryDirectory, in: .systemDomainMask).first?.appendingPathComponent("Fonts"),
            let directoryInGlobal = FileManager.default.urls(for: .libraryDirectory, in: .localDomainMask).first?.appendingPathComponent("Fonts"),
            let directoryInUser = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first?.appendingPathComponent("Fonts")
                
        else {
            return []
        }
        return [directoryInSystem, directoryInGlobal, directoryInUser]
    }
    
    /// 指定したディレクトリ内のフォントのfileURLを取得
    static private func loadFonts(in directory: URL) -> [URL] {
        guard let enumerator = FileManager.default.enumerator(
            at: directory,
            includingPropertiesForKeys: [.isRegularFileKey],
            options: [.skipsHiddenFiles, .skipsPackageDescendants]) else {
            return []
        }
        
        var fontURLs = [URL]()
        let extensions = ["otf", "ttf", "ttc"]
        for case let fileURL as URL in enumerator {
            if extensions.contains(fileURL.pathExtension) {
                fontURLs.append(fileURL)
            }
            fontURLs.append(fileURL)
        }
        return fontURLs
    }
    
    /// 検索対象となるFontsディレクトリ内の全フォントのURLを取得
    static func loadAllFontsInLocal() -> [URL] {
        var urls: [URL] = []
        fontsDirectories.forEach { directory in
            urls += loadFonts(in: directory)
        }
        urls.sort { $0.path() < $1.path() } // AtoZに並べ替え
        return urls
    }
    
}

SwiftのプロジェクトからC++の静的ライブラリを利用する

概要

  • Swiftのプロジェクトに対して、C++で書かれたライブラリのプロジェクトを追加して、アプリのビルド時にライブラリもビルドされるようにしたい

参考

手順

  • 下記の通りプロジェクトにライブラリのプロジェクトを追加

image

  • ライブラリのバイナリをリンクさせる

image

  • ライブラリのヘッダーファイルが含まれるディレクトリを指定

image

  • xxx-Bridging-Header.hを作成し利用するライブラリを記載する
#import "<library-name>.h"
  • 以上でSwiftから呼び出せるようになる(Swift側でのimportは不要)