xcode 从Mac App捆绑包访问/资源库/应用程序支持的权限

vuktfyat  于 2022-11-18  发布在  Mac
关注(0)|答案(2)|浏览(215)

我有应用程序套件(用Unity 3D构建,如果这是相关的话)我能够使用ProductBuild创建一个.pkg安装程序,并在应用程序商店上分发,没有问题。但是,这款应用下载并缓存了大量的媒体,并且有一些可选的配置文件需要在机器上的所有用户之间共享。根据苹果的文档,这些配置文件应该放在/Library/应用程序支持目录和/Library/Caches中的媒体。我已经制作了该应用程序的修改版本,它使用这些目录,而不是沙盒应用程序可以访问的目录,但它没有权限访问/Library目录,除非我以root身份运行该应用程序,这是一个不现实的选择。
我在谷歌上搜索了几个小时,但我似乎找不到任何关于创建这样一个安装程序的信息。我确实读过this answer,它有一个安装程序的截图,该安装程序可以为所有用户安装,但要么是我缺少了一些启用该选项的选项,要么是该截图已经过时,因为我似乎无法创建一个提供该选项的.pkg。
所以我想我的问题可以归结为:我如何打包我的应用程序,以便所有用户都可以安装它,并拥有对/Library/Application Support/{app name}的读写权限,或者是否有其他首选方法在同一台计算机上的多个用户之间共享配置文件和/或媒体?

hivapdat

hivapdat1#

对于其他遇到类似问题的人,正确的答案是您不能使用productbuild完成此操作,但可以使用pkgbuild。
我的应用商店productbuild构建步骤如下所示:

productbuild --component "{mystoreapp.app/}" /Applications --sign "{signing identity}" "{mystorepkg.pkg}"

pkgbuild得相应打包命令如下所示:

pkgbuild --component "{mymodifiedapp.app/}" --sign "{signing identity}" --ownership preserve --scripts "{path/to/my/scripts}" --identifier {com.yourcompany.yourapp} --version "{versionNumber}" --install-location /Applications "{mymodifiedpkg.pkg}"

请注意,此处的签名是可选的,因为它将在存储区之外分发。其中{path/to/my/scripts}中有一个名为postinstall的文件,如下所示:

#this function creates a directory if it doesn't exist
create_directory() {
    if [[ ! -d "$1" ]]
    then
            if [[ ! -L "$1" ]]
            then
                    echo "directory $1 doesn't exist. Creating now"
                    mkdir "$1"

                    echo "directory $1 created"
            else
                    echo "directory $1 exists"
            fi
    fi
}

#this function gives all users read and write (and execute) access to the directory
fix_dir_permissions() {
    chmod 777 "$1"
}

baseDirName="/Library/Application Support/{your app name bere}"

subDirs[0]="$baseDirName/{sub dir here}"

#create base directory
create_directory "$baseDirName"

#create all subdirectories and give permissions
for subDir in "${subDirs[@]}"
do
    create_directory "$subDir"
    fix_dir_permissions "$subDir"
done

exit 0

此脚本将在安装结束后运行,并将创建您的应用程序支持目录以及您需要的任何子目录,并更改它们的权限,以便所有用户都可以访问它们。

afdcj2ne

afdcj2ne2#

我通过创建一个小的帮助应用程序解决了同样的问题,在需要访问“应用程序支持”的任何时候,都可以从主程序中调用这个帮助程序。这个帮助程序是使用AuthorizationExecuteWithPrivileges从主程序中派生出来的。它只调用函数来创建目录和设置权限。所以所有的操作都是在主应用程序中完成的。而不是从安装程序包。AuthorizationExecuteWithPrivileges(是的,它正式弃用)然后显示一个Macos系统窗口,要求输入密码等。
对于这一部分,这里有一个很好的实现:https://github.com/sveinbjornt/STPrivilegedTask/
重要的是:

  • 等待直到调用的程序完成
  • 然后再次等待,直到文件夹存在(可能需要几毫秒)

我花了很长时间来完成这个,所以我在这里分享它。虽然应用程序是C++,但这里的代码必须使用obective-c。请看我在这里的签名和公证:如何公证包含内嵌助手的应用程序捆绑包?
帮助程序:

#import <Foundation/Foundation.h>
#include <iostream>
#include <fstream>

int main(int argc, const char * argv[]) {
    
    @autoreleasepool {
        NSString *supportDirectory  = [NSString stringWithFormat:@"%s", argv[1] ];
        NSError *error = nil;
        BOOL success = [[NSFileManager defaultManager] createDirectoryAtPath:supportDirectory withIntermediateDirectories:YES attributes:nil error:&error];
        if (!success)
                return -1;
        BOOL success2 = [[NSFileManager defaultManager] setAttributes:@{ NSFilePosixPermissions : @0777 } ofItemAtPath:supportDirectory error:&error];
    }
    return 0;
}

调用方进程:

void macCheckCreateFolderAdmin(std::string path)
{
       NSString *supportDirectory  = [NSString stringWithFormat:@"%s", path.c_str() ];
       NSError *error = nil;
       BOOL success;
       if ([[NSFileManager defaultManager] fileExistsAtPath: supportDirectory])
        return;
    
        char *args[] =
            {
              const_cast<char *>(path.c_str()),
              NULL
            };
        AuthorizationRef authorizationRef;
        OSStatus status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef);
    
        NSString *nsExecPath = NSProcessInfo.processInfo.arguments[0];
        const char *applFolder = [nsExecPath UTF8String];
        std::string s = std::string(applFolder);
        std::size_t found = s.rfind("/");
        if( found != std::string::npos)
            s = s.substr(0, found + 1);
        s += "myHelperProgram";
        FILE *outputFile = nullptr;
        OSStatus status2 = AuthorizationExecuteWithPrivileges(authorizationRef, s.c_str(), kAuthorizationFlagDefaults, args, &outputFile);
        if(status2 != 0)
            return;
    
        int processIdentifier = fcntl(fileno(outputFile), F_GETOWN, 0);
        pid_t pid = 0, count = 0;
        while(count < 30 && (pid = waitpid(processIdentifier, &status, WNOHANG)) == 0)
        {
            count ++;
            usleep(200 * 1000);
        }
    }
}

相关问题