拡張子 or MIME から UTI を取得 Cocoa AppleScript [01] with Swift
ASOC [01] 【macOS11以降限定】拡張子 or MIME から UTI を取得
macOS11.0 (iOS14) 以降利用可能な新 "UniformTypeIdentifiers" framework の UTType クラスにて、拡張子 or MIME から UTI を取得!
UTI (Uniform Type Identifier) は macOS10 (iOS13) 以前 CoreServices や MobileCoreServices などを利用して取得していましたが 非推奨となったため、その代替フレームワークが "UniformTypeIdentifiers" となります。
kUTTypePlainText のような以前のフレームワークで参照できた kUTType は CFString で宣言されており、 Cocoa の NSString クラスとの相互変換が面倒でした。
筆者もCFStringが問題で 拡張子からUTI取得を断念し、(拡張子を含めた)ファイルからUTIを取得するAppleScriptを紹介した過去が...
コマンドライン版ですが、同機能の Swift コードと Cocoa Objective-C コードを追記!
Cocoa AppleScript [01] 【macOS11以降限定】拡張子 or MIME から UTI を取得
まず、[アプリケーション]-[ユーティリティ] フォルダ内の「スクリプトエディタ.app」を起動して、左下の [新規書類]ボタン をクリック。
AppleScriptコードを貼り付けて、[command]+[R] で即!テスト可能
(1) 以下のAppleScriptコード表示部にマウスのカーソルを重ねるかクリックすると 右上に[コードをコピーする]ボタンが表示されるため、クリックしてコードをコピー。
(2) スクリプトエディタ画面内をクリックすると、画面上部でキャレットが点滅しているはずです。 この箇所にコードを挿入するためクリック後、 [command]+[V] でコードを貼り付け。
(3) [command]+[R] で、即!テスト可能
(4) 拡張子 "xlsm" あるいは MIME "application/pdf" を置き換えて [command]+[R] で即反映 (MIMEが不明なら、「pdf wiki」で検索すれば、wikipedia画面の右上に表示)
(5) 必要なら、 [command]+[S] にて(AppleScriptコードを)名前を付けて保存
-- Copyright 2021- ataruchi. [ https://twitter.com/ataruchi ]
-- 拡張子 or MIME から、UTI (Uniform Type Identifier) を取得 with Cocoa AppleScript (with ASOC)
-- 新 "UniformTypeIdentifiers" framework 利用のため、macOS11[Big Sur]以降 限定
use AppleScript version "2.7" --But macOS11〜 for use new "UniformTypeIdentifiers" framework
use scripting additions
use framework "Foundation"
use framework "UniformTypeIdentifiers" --New framework for UTI, macOS11.0+ [Big Sur or later]
property UTType : a reference to current application's UTType --new Class, macOS11.0+
--property NSString : a reference to current application's NSString
set theResult to getUtiFromExt("xlsm") --マクロ付きExcel、拡張子
set theResult to theResult & return --改行コードを挿入
set theResult to (theResult & getUtiFromMime("application/pdf")) --pdf、MIME
return theResult
on getUtiFromExt(theExt) --macOS11 or later only, for use "UniformTypeIdentifiers" framework
set theUTType to UTType's typeWithFilenameExtension:theExt --create UTTyp's object
if theUTType = (missing value) then return ("fail to search UTI: " & theExt)
return (theUTType's identifier as string)
end getUtiFromExt
on getUtiFromMime(theMime) --macOS11 or later only, for use "UniformTypeIdentifiers" framework
--set theMimeStr to NSString's stringWithString:theMime --create NSString's object
--set theUTType to UTType's typeWithMIMEType:theMimeStr --create UTTyp's object
set theUTType to UTType's typeWithMIMEType:theMime --create UTTyp's object
if theUTType = (missing value) then return ("fail to search UTI: " & theMime)
return (theUTType's identifier as string)
end getUtiFromMime
[command] + [Q] にて スクリプトエディタ を終了し、AppleScriptコードを再利用しなければ ダイアログ左下の [削除] ボタンをクリック!
既に最終のコードを保存済みならダイアログは表示されません。 また、ダイアログから名前を付けて保存することも可能。
VBAとは異なり AppleScript に関しては初心者のため、不具合があればコメント等で教えて頂けると嬉しいです。
勉強中の Swift コード(コマンドライン)版
Swiftコードのコンパイルには Xcode (無料)のインストールが必要ですが、40GB〜42GBの空き容量がないと App Storeからはインストールできない らしい。
(Apple Developers公式サイトからダウンロードすれば) 12GB ほどの最小版をインストール可能だそうです(Web検索すれば、出てくるはず)
いずれにしろ、インストールするのであれば 空き容量に 注意してください!
【ダウンロードリンクあり】 getUtiFromExt(main.swift) getUtiFromMime(main2.swift)
//
// main.swift
// getUtiFromExt
//
// Created by ataruchi on 2021/11/07.
//
import Foundation
import UniformTypeIdentifiers //New framework for UTI, macOS11.0+ [Big Sur or later]
if let argument = CommandLine.arguments.dropFirst().first {
let ext: String = argument
if let str = UTType.init(filenameExtension: ext) {
print(str)
}
else {
print("fail to search UTI: \(argument)")
}
}
上記 "main.swift" ファイルのダウンロードは こちらから!
上記リンクを右クリックして「リンク先のファイルをダウンロード」等を選択してダウンロード可能。 ( "Google Chrome" ブラウザの場合、上記リンクを右クリックして「名前を付けてリンク先を保存」を選択してダウンロード )
(注) [ Unicode(UTF-8) 、改行コードは LF ] ファイル置き場として、筆者の旧ブログを利用
//
// main2.swift
// getUtiFromMime
//
// Created by ataruchi on 2021/11/07.
//
import Foundation
import UniformTypeIdentifiers //New framework for UTI, macOS11.0+ [Big Sur or later]
if let argument = CommandLine.arguments.dropFirst().first {
let mime: String = argument
if let str = UTType.init(mimeType: mime) {
print(str)
}
else {
print("fail to search UTI: \(argument)")
}
}
上記 "main2.swift" ファイルのダウンロードは こちらから!
上記リンクを右クリックして「リンク先のファイルをダウンロード」等を選択してダウンロード可能。 ( "Google Chrome" ブラウザの場合、上記リンクを右クリックして「名前を付けてリンク先を保存」を選択してダウンロード )
(注) [ Unicode(UTF-8) 、改行コードは LF ] ファイル置き場として、筆者の旧ブログを利用
「ターミナル.app」での コンパイル方法
ダウンロードした "main.swift" と "main2.swift" の2ファイルを、ホームフォルダ( /Users/username/ )へコピーしておきます。 (注)usernameはユーザーによって異なります
コンパイルして Unix実行ファイル( getUtiFromExt と GetUtiFromMime )ができれば、上記2ファイルは別のフォルダに移動か 削除してもかまいません。
cd $home
swiftc -o getUtiFromExt main.swift
swiftc -o getUtiFromMime main2.swift
Unixコマンドを実行する場合 問題なければ 次行に % のみ表示され、エラー発生時のみメッセージが表示されます。 覚えておいてください。
慣れない方はコマンド文字列を コピー&ペースト 後 [return]キーを押下、 [return] キーのみを叩くと、 % のみの行を表示。
(1) [アプリケーション]-[ユーティリティ] フォルダ内の「ターミナル.app」を起動。
(2) 通常、ホームディレクトリ(ホームフォルダ)がカレントディレクトリで開くはずですが、念のため cd $home [return] にて移動。
(3) swiftc -o getUtiFromExt main.swift [return] にて main.swift をコンパイルし、「getUtiFromExt」Unix実行ファイルを作成。
(4) swiftc -o getUtiFromMime main2.swift [return] にて main2.swift をコンパイルし、「getUtiFromMime」Unix実行ファイルを作成。
"Finder" でホームフォルダ内に getUtiFromExt と GetUtiFromMime があるか確認! 無ければ、もう一度実行してみてください。
「ターミナル.app」での 実行方法
引き続き、「ターミナル.app」での作業となります!
/Users/wito/getUtiFromExt xlsm
org.openxmlformats.spreadsheetml.sheet.macroenabled
/Users/wito/getUtiFromExt swift
public.swift-source
/Users/wito/getUtiFromMime 'application/pdf'
com.adobe.pdf
筆者のホームディレクトリ(フォルダ)は /Users/wito/ で、太字の部分は ユーザー毎に異なります。
/Users/wito/getUtiFromExt あるいは /Users/wito/getUtiFromMime を [command]+[C] でコピーしておくと、入力ミスが減るのでオススメです。
[command]+[V] で貼り付けして「カーソルキーの ▶︎ 」を叩いた後に [space]キーを叩き、残りの拡張子やMIME文字列を入力後、最後に [return]キーを押下。
( 空白文字 や ややこしい文字を含む場合は、 'application/pdf' あるいは "application/pdf" のように括る必要あり )
次行に UTI が表示されます!
【注意】パスが通っているディレクトリに Unix実行ファイル をコピー(移動でも可)すれば 先頭の /Users/wito/ の部分を入力する必要はありませんが、/usr/local/bin/ デイレクトリが macOS11 では無くなっていたため 止めました。 適切なデイレクトリにコピーできる方は、コンパイル時の swiftc -o の後のパラメータで任意(ただし、Unixコマンド等と重複しないこと)に Unix実行ファイル名を変えれば、入力が楽になることでしょう!
最後に [command]+[Q] などで、「ターミナル.app」アプリを忘れずに終了してください!
【参考】(Cocoa) Objective-C コード(コマンドライン)版
Cocoa AppleScript に置き換えるのであれば Objective-C コードの方が分かりやすいのだけど、最近は Swift のサンプルコードばかりで...
Swift の String と Cocoa (Objective-C) の NSString は全く別物のクラスで、戸惑うことがあります。 Swift の場合、両方使えるし...
ASOC 完全対応なのは Objective-C で間違いなくて、今回 同じ UTType クラスでも Swift と Objective-C(つまり ASOC)でメソッド名や返り値が微妙に違っていてややこしかった。
Objective-C は昔ちょっとかじったことがあって何となく理解できるのですが、時代のながれなので Swift をもっと勉強しないといけないようです!
現在は ①Swiftサンプルコード → ②Cocoa Objective-Cコード → ③Cocoa AppleScriptコード に変換してるんですが、慣れれば ① → ③ 対応できるか 不安かも?
main.m [ getUtiFromExtObjC ]
//
// main.m
// getUtiFromExtObjC
//
// Created by ataruchi on 2021/11/08.
//
//「ターミナル.app」でのコンパイルは、以下で可能!
//gcc -o suti main.m -framework Foundation -framework UniformTypeIdentifiers
#import <Foundation/Foundation.h>
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
if (argc < 2) {
printf("No parameter.\n"); //引数なし
return 0;
}
// [arguments objectAtIndex:0] はコマンド名で、objectAtIndex:1 以降が引数
NSArray *arguments = [[NSProcessInfo processInfo] arguments];
NSString *ext = [NSString stringWithString:[arguments objectAtIndex:1]];
NSString *uti;
if ((uti = [[UTType typeWithFilenameExtension:ext] identifier])) {
printf("%s\n",[uti UTF8String]); //UTI取得 成功
}
else {
printf("fail to search UTI: %s\n",[ext UTF8String]); //UTI取得 失敗
}
return 0;
}
}
main2.m [ getUtiFromMimeObjC ]
//
// main2.m
// getUtiFromMimeObjC
//
// Created by ataruchi on 2021/11/08.
//
//「ターミナル.app」でのコンパイルは、以下で可能!
//gcc -o sutimime main2.m -framework Foundation -framework UniformTypeIdentifiers
#import <Foundation/Foundation.h>
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
if (argc < 2) {
printf("No parameter.\n"); //引数なし
return 0;
}
// [arguments objectAtIndex:0] はコマンド名で、objectAtIndex:1 以降が引数
NSArray *arguments = [[NSProcessInfo processInfo] arguments];
NSString *mime = [NSString stringWithString:[arguments objectAtIndex:1]];
NSString *uti;
if ((uti = [[UTType typeWithMIMEType:mime] identifier])) {
printf("%s\n",[uti UTF8String]); //UTI取得 成功
}
else {
printf("fail to search UTI: %s\n",[mime UTF8String]); //UTI取得 失敗
}
return 0;
}
}
UTI は Mac で プログラミング をする上で重要で、ファイル選択ダイアログでのファイル種別限定や ドラッグ&ドロップ実装時の登録にて 必要!
macOS11 Big Sur (iOS14) 以降限定とはなりますが、直接 UTI を指定するのではなく 「拡張子」や「MIME」を指定して コード内部で間接的に UTI を取得するとスマートだと思います。
旧フレームワークの CoreServices や MobileCoreServices の一部は既に非推奨のため、今後利用できなくなるはずです。 早めに UniformTypeIdentifiers フレームワークに対応しておけば、この先安心かと...
早く macOS12 が安定すると良いですね。(筆者は、それまで macOS11.6.1 を使用) 愛用の Mac mini 2014 でも遅くなりませんように! macOS11 では intelチップ以外のMacで AppleScript が低速なコアのみで実行されるというバグ? があったため、 macOS12 の AppleScript 実行速度にビックリするそうですよ! intelチップのMacでも少々速くなるらしいです。
最後まで読んでいただき、ありがとうございます。 また、お越しくださいませ。
// アタル