5

私は現在、AppleScriptアプリケーションを構築中です。(これは、AppleScript Editorを使用してAppleScriptを作成し、そのスクリプトをアプリケーションとして保存することによって作成された、プレーンなAppleScript「アプリケーション」であることに注意してください)。このアプリでは、現在のユーザーが最近開いたファイルのファイルパスを知る必要があります。これまでにさまざまな方法を試しましたが、必要な情報が得られていないようです。

私は次のことを試しました:

  • ファイルを試してみましたが、com.apple.recentitems.plistこのファイルに含まれているファイルパス情報は16進形式のようで、ASCIIに変換すると大量のmumbo-jumboでいっぱいになり、mumbo-jumboの形式は別のものに変わるようです。ファイルと別のコンピューター。
  • unixfindコマンドを使用して、過去に開いたファイルをフィルタリングしようとしましたが、ここでは、最近変更したファイルと最近アクセスしたファイルのどちらかを選択でき、最近開いたファイルは選択できません。最近変更されたファイルには、変更されていない開いたファイル(開いているが編集されていない画像など)は含まれません。最近アクセスしたファイルには、Finderに表示されているすべてのファイルがサムネイルビューで表示されているようです。ユーザーが開いた。
  • 私はObjective-CとLaunchServices/LSSharedFileList.h取得するためのファイル(この回答kLSSharedFileListRecentDocumentItemsと同様)に挑戦しようとしましたが、これまでObjective-Cを使用したことがないため、これで適切に機能するものを取得できませんでした。

現在のユーザーのために最近開いたファイルのリストを取得するために誰かが提供できる助けをいただければ幸いです。さらに、最近変更されたファイルのリストをテキストファイルに書き込むことができるようにするための助けがあれば素晴らしいでしょう。

4

3 に答える 3

1

AppleScript

そのafaik用のAppleScript API(LSSharedFileListに相当)はありません..objCコードを呼び出すか(以下のobjCスニペットを参照)、または..少しハックなIMOであるplistを読むだけです:)

客観的-c

サンドボックス化されていないアプリの場合は、LSSharedFileListAPI を使用します。これが最も適切な方法です。

@implementation DDAppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    LSSharedFileListRef list = LSSharedFileListCreate(NULL, kLSSharedFileListRecentDocumentItems, 0);
    CFArrayRef items = LSSharedFileListCopySnapshot(list, NULL);

    for(int i=0; i<CFArrayGetCount(items); i++) {
        LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(items, i);

        //get items properties... for demo I just get name
        NSString *name = (__bridge_transfer NSString*)LSSharedFileListItemCopyDisplayName(item);

        NSLog(@"%@", name);
    }
}

@end

ただし、サンドボックスでは機能しません-そして実際の回避策はありません(あなたが言ったように、plistを直接読むことはできますが...それは少しハックです:D PLUSアップルはおそらくあなたにそれをさせません!)

于 2013-01-01T03:02:42.810 に答える
1

あなたの解決策はおそらく機能しますが、おそらく私が思いついたものの方が実行可能かもしれません.

あなたが思いついた提案された 3 つのオプションのうち、実際にLSSharedFile*コマンドが最良の解決策です。

AppleScript スクリプト バンドル (.scptd) と、アプリケーション バンドル (.app) として保存できるスクリプトの出現により、バンドル内にカスタム実行可能ファイルを非常に簡単に含めることができます。その結果、AppleScript だけやデフォルトの BSD サブシステム ツールだけでは達成できなかった場合でも、これらの実行可能ファイルを利用して必要なことを達成できます。

そこで、Xcode で、次のコードを使用する新しい「Foundation Tool」プロジェクトを作成しました。

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        UInt32 resolveFlags = 0;
        NSArray *arguments = [[NSProcessInfo processInfo] arguments];
        if (arguments.count > 1) {
            NSArray *revisedArguments = [arguments
                        subarrayWithRange:NSMakeRange(1, arguments.count - 1)];
            for (NSString *arg in revisedArguments) {
                if ([arg isEqualToString:@"--noUserInteraction"]) {
                    resolveFlags |= kLSSharedFileListNoUserInteraction;
                } else if ([arg isEqualToString:@"--doNotMountVolumes"]) {
                    resolveFlags |= kLSSharedFileListDoNotMountVolumes;
                }
            }
        }
        LSSharedFileListRef sharedFileListRef = LSSharedFileListCreate(NULL,
                              kLSSharedFileListRecentDocumentItems, NULL);
        NSArray *sharedFileListItemRefs =
           (NSArray *)LSSharedFileListCopySnapshot(sharedFileListRef, NULL);
        for (id itemRef in sharedFileListItemRefs) {
            NSURL *resolvedURL = nil;
            LSSharedFileListItemResolve((LSSharedFileListItemRef)itemRef,
                 resolveFlags, (CFURLRef *)&resolvedURL, NULL);
            if (resolvedURL) {
                printf("%s\n", resolvedURL.path.fileSystemRepresentation);
                [resolvedURL release];
            }
        }
        if (sharedFileListRef) CFRelease(sharedFileListRef);
        [sharedFileListItemRefs release];
        return EXIT_SUCCESS;
    }
}

このコードはあなたのコードと似ていますが、結果を中間ファイルに書き込む代わりに、ファイル パスを標準出力に出力するだけです。これにより、AppleScript 側でのコーディングが大幅に簡素化されるはずです。この Xcode プロジェクトをビルドrecentItemsFinaglerすると、アプリケーション バンドルの代わりに名前が付けられた単一の「Unix 実行可能ファイル」が作成されます。

このビルドされた実行可能ファイルを AppleScript で利用するには、まずスクリプトがスクリプト バンドルまたはアプリケーションとして保存されていることを確認してから、Bundle Contents下の画像のようにツールバー項目を有効にする必要があります。

ここに画像の説明を入力

そのツールバー項目をクリックすると、スクリプト バンドルまたはアプリケーション バンドルの内容を示す引き出しが表示されます。カスタム実行可能ファイルを追加するには、下の画像のように Finder からドラッグ アンド ドロップするだけです。

ここに画像の説明を入力

これにより、次のようにスクリプト バンドルにコピーされます。

ここに画像の説明を入力

実行時にこの実行可能ファイルを見つけるpath to resourceには、 の一部である AppleScript コマンドを使用できますStandardAdditions.osaxpath to resource(スクリプトでコマンドを使用する方法によっては、Finder でスクリプトをダブルクリックして実行するのではなく、AppleScript エディタ内からスクリプトを実行すると、「リソースが見つかりません」というエラーが発生する場合があることに注意してください。このタイプのエラーが発生した場合は、まずスクリプトへのすべての変更を保存したことを確認してから、AppleScript エディタを終了し、Finder でスクリプト アプリケーションをダブルクリックして起動します。実行を終了し、AppleScript Editor を再度開いてから、スクリプト アプリケーションを再度開いてから、AppleScript Editor 内から実行してみて、動作するかどうかを確認してください)。

したがって、これrecentItemsFinaglerを AppleScript で利用するには、次のようにします。

property recentItemsFinagler : missing value

if (recentItemsFinagler = missing value) then
    set recentItemsFinagler to (path to resource "recentItemsFinagler")
end if

set toolPath to quoted form of POSIX path of recentItemsFinagler

set recentItemsString to (do shell script toolPath & " --noUserInteraction --doNotMountVolumes")

set recentItemsPaths to paragraphs of recentItemsString

この AppleScript を 1 行ずつ調べて、何をしているのかを説明します。最初にグローバル プロパティを作成し、recentItemsFinaglerその初期値を に設定しますmissing value。(missing valueは、Objective-C に相当する AppleScript ですnil)。

ご存じないかもしれませんが、AppleScript のグローバル プロパティは他の言語のグローバル変数に似ていますが、重要な点が 1 つあります。スクリプトを実行してプロパティに値を割り当てると、その値は実際にはスクリプト ファイル自体に保存されます。次回スクリプトを実行するまで保持されます。

スクリプトは最初に が と等しいかどうかを確認し、recentItemsFinagler等しい場合はAppleScript参照であるmissing valueの結果に設定します。これは、名前の変更や、あるフォルダーから別のフォルダーへの移動などの変更を正常に追跡できるという点で、Finder のエイリアスに似ています。代わりに単純な文字列として保存し、この AppleScript アプリケーション バンドルをドキュメント フォルダからデスクトップに移動した場合、パスは無効になり、スクリプトが実行されるたびにプロパティを更新する必要があります。(path to resource "recentItemsFinagler")alias

とにかく、文字列であるrecentItemsStringAppleScriptdo shell script recentItemsFinaglerツールの結果に設定します。これを、パスを表す文字列の AppleScript リストに変換するには、次のparagraphs ofコマンドを使用します。

したがって、スクリプトまたは AppleScript アプリケーションのバンドル内に実行可能ファイルを含めることで、10 行未満のコードで目的の結果を得ることができます。

サンプル プロジェクト: RecentItemsFinagler.zip

于 2013-01-04T01:55:03.043 に答える
0

私自身の質問に答えるのは少し皮肉なことですが、Daij-Djan と多くのグーグルのおかげで、私は自分の答えを見つけました。間違いなく、それを行う最もクリーンな方法ではありませんが、必要なことは実行します。これが将来誰かを助けることができることを願っています!

#import "AppDelegate.h"

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    LSSharedFileListRef list = LSSharedFileListCreate(NULL, kLSSharedFileListRecentDocumentItems, 0);
    CFArrayRef items = LSSharedFileListCopySnapshot(list, NULL);


    NSArray *paths = NSSearchPathForDirectoriesInDomains
    (NSLibraryDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];

    NSString *fileName = [NSString stringWithFormat:@"%@/Application Support/MyAppName/RecentFiles.txt",documentsDirectory];

    NSString *content = @"";
    [content writeToFile:fileName
              atomically:NO
                encoding:NSStringEncodingConversionAllowLossy
                   error:nil];

    for(int i=0; i<CFArrayGetCount(items); i++) {
        LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(items, i);

        CFURLRef itemURL = NULL;
        LSSharedFileListItemResolve(item, kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes, &itemURL, NULL);

       if (itemURL != (NULL)) {

        NSString *str = [NSString stringWithFormat:@"%@\n", itemURL]; //get text from textField

            NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:fileName];

            // move to the end of the file
            [fileHandle seekToEndOfFile];

            // convert the string to an NSData object
            NSData *textData = [str dataUsingEncoding:NSUTF8StringEncoding];

            // write the data to the end of the file
            [fileHandle writeData:textData];

            // clean up
            [fileHandle closeFile];


             }

    }
    exit(0);
}

@end
于 2013-01-01T09:08:00.167 に答える