如何将文件从沙盒应用程序正确复制到应用程序脚本文件夹?

Posted

技术标签:

【中文标题】如何将文件从沙盒应用程序正确复制到应用程序脚本文件夹?【英文标题】:How to properly copy files to Application Scripts folder from Sandboxed App? 【发布时间】:2020-06-05 10:53:55 【问题描述】:

我真的很困惑如何正确复制文件并授予执行权限,例如来自沙盒应用程序的 AppleScript 文件。我已经阅读了几篇文章和主题,但我阅读的越多,它就越让我感到困惑。

任务

我的应用需要从.scpt 文件运行一个非常简单的AppleScript。为此(如果我做对了),我需要将此文件复制到Users/thisUser/Library/Application \Scripts/.com.developerName.appName/。在我可以与此文件夹交互之前,用户需要授予对该文件夹的访问权限。这可以通过向用户显示NSOpenPanel 来完成,他可以在其中选择路径。确认应用程序可以访问该路径后,我可以复制文件并稍后运行脚本(应用程序沙箱 用户选择的文件 必须是读/写)。到目前为止一切顺利。

问题

我发现显示一个带有空文件夹的 Finder 窗口来选择对用户非常不友好,所以我想知道是否还有什么可以做的。关于这个问题,我发现的最接近的是拖放文件夹“进入应用程序” - 可以在here. 找到详细信息

我想我不是唯一一个创建需要运行特定脚本的(沙盒)应用程序的人,我不敢相信上述方法是唯一可能的解决方案!?因此,

我能不能只拥有一个带有“确定”按钮的窗口和上面的一些信息,应用程序需要权限才能写入该文件夹而不显示整个 Finder 窗口?

当我四处寻找解决方案时,我还发现了应用程序本身的几个设置。不幸的是,这里的文档非常有限,我无法真正找出具体设置的实际作用以及如何测试它们(诚然,这是因为这是我第一个用于 OSX 的应用程序,我基本上不知道我是什么正在做)。其中之一是应用构建阶段设置中的复制文件选项:

这对我来说确实很有希望,因为我认为如果我安装应用程序,它会自动将文件复制到脚本目标(可能带有某种用户提示)并且我可以使用它。但它什么也没做。即使我取消选择仅在安装时复制设置,任何时候都不会发生复制。我还尝试了下拉菜单中提供的不同目标文件夹

不幸的是我也在这里

找不到目的地是什么 也没有将该文件复制到build 上的任何目标文件夹。

我知道这里的人不太喜欢详细回答这样的问题,因为这可能是我方面缺乏知识,但如果有人能在至少帮助我进入正确的方向并引导我找到一些解决我的问题的资源!

谢谢!

【问题讨论】:

【参考方案1】:

好吧,我似乎找到了一个(至少对我而言)似乎或多或少对用户友好且符合 Apple 沙盒指南的解决方案。

再说一次,我对使用 Xcode 和 SwiftUI 进行应用程序开发非常陌生,所以我不确定这个解决方案是否是 100%“正确的做法”。但由于我花了很长时间才发现这一点,也许其他人可以使用它并加快开发速度!

解决方案

就像我在上面的问题中提到的那样,我试图摆脱(在我看来)非常烦人的NSOpenPanel Finder 提示,用户应该在其中选择文件夹。我进一步询问了应用程序 Build Phase 选项卡中的 Copy Files 设置 - 结果证明这是解决方案!不幸的是,我仍然对下拉列表中显示的目的地列表没有任何线索,但选择 Absolute Path 并插入

Users/$USER/Library/Application Scripts/$PRODUCT_BUNDLE_IDENTIFIER

完成了任务!该文件在每次构建时都会复制到应用程序的 Application Scripts 目录中,我可以从中运行沙箱外的脚本。 ?

下一步是创建一个使用NSUserScriptTask 执行脚本的类

import Foundation

class ExecuteAppleScript 

    var status = ""

    private let scriptfileUrl : URL?


    init() 
        do 
            let destinationURL = try FileManager().url(
                for: FileManager.SearchPathDirectory.applicationScriptsDirectory,
                in: FileManager.SearchPathDomainMask.userDomainMask,
                appropriateFor:nil,
                create: true)

            self.scriptfileUrl = destinationURL.appendingPathComponent("CreateMailSignature.scpt")
            self.status = "Linking of scriptfile successful!"

         catch 
            self.status = error.localizedDescription
            self.scriptfileUrl = nil
        
    

    func execute() -> String 
        do 
            let _: Void = try NSUserScriptTask(url: self.scriptfileUrl!).execute()
            self.status = "Execution of AppleScript successful!"
         catch 
            self.status = error.localizedDescription
        

        return self.status
    

然后我创建了一个处理请求的按钮视图

import SwiftUI

struct GenerateSignatureButtonView: View 

    @State var status = ""

    var body: some View 
        VStack(alignment: .center) 
            Button(action: 
                self.status = ExecuteAppleScript().execute()
            )
            
                Text("Generate Signature")
            
            Text("\(self.status)")
        
    


struct GenerateSignatureButtonView_Previews: PreviewProvider 
    static var previews: some View 
        GenerateSignatureButtonView()
    

单击按钮时,会弹出一个窗口,该应用程序希望访问控制(在我的情况下)邮件应用程序。

每次用户关闭应用程序、重新打开应用程序并再次单击按钮时,都会重复此用户提示。我想这可以通过Security-Scoped-Bookmarks 以某种方式进行管理,但我还不确定如何。此外,错误处理在此示例中并没有真正起作用,因为弹出窗口出现在 成功 消息出现在状态字段中。这可能是另一件要弄清楚的大事......异步?

好吧,希望这会有所帮助!

【讨论】:

弗洛里安,感谢分享!我也一直在挖掘这方面的信息,所以我很高兴看到你是如何解决问题的。一个(新蜜蜂)问题:当用户从 Apple Store 安装时,您是否验证了您的解决方案是否也有效?即:当有人第一次下载你的应用程序时,脚本会自动安装在“Application Scripts”文件夹中吗? 这个解决方案没用。该文件只会复制到您的开发者机器上... @TamásZahola 好吧,为什么它只能在开发机器上工作?根据 App Developer Docs,这篇文章的目的地正是应用程序相关文件所在的位置 - 在每台机器上,关于发布此答案的日期。此外,我已经向朋友和家人分发了许多应用程序,包括这个解决方案——它曾经(现在仍然)在所有不同的机器上运行。 您正在向您的 Xcode 项目添加一个 Copy Files 构建阶段,该阶段将在构建目标时由 Xcode 执行。当您从此应用创建 .app 包时,根本没有机制可以将此文件放置到用户计算机上的必要位置。

以上是关于如何将文件从沙盒应用程序正确复制到应用程序脚本文件夹?的主要内容,如果未能解决你的问题,请参考以下文章

PayPal - 使用 REST API 从沙盒切换到真实账户

贝宝应用程序。从沙盒到直播

Unity3d StreamingAssets资源复制到沙盒

将闪电页面从沙盒部署到生产环境

从沙盒命令行应用程序获取当前工作目录

从沙盒应用程序锁定 Macbook 屏幕