MAC OS X中遇到的授權(quán)問題

關(guān)于MAC OS X##

去年十月份從iOS開發(fā)轉(zhuǎn)到OS X開發(fā),OS X主要由五大API來開發(fā),分別是`Cocoa`腥椒、`Carbon`虽惭、`POSIX`、`X11`和`Java`接谨。目前我用的是`Cocoa`來開發(fā)摆碉,OS X開發(fā)中考慮的問題更多一些,網(wǎng)上的資料更少一些脓豪,遇到問題后最好的解決辦法就是查看[官方文檔](https://developer.apple.com/search/?q=mac%20os%20x)巷帝。

什么時候需要授權(quán)?

在OS X開發(fā)中扫夜,我們會經(jīng)常遇到權(quán)限的問題楞泼,比如你安裝APP的時候,你如你需要刪除一些配置文件的時候都需要權(quán)限笤闯,不然就無法操作堕阔,我們的項目中需要做一個卸載工具和退域工具,里面涉及到刪除配置文件以及退出進程等一些需要權(quán)限的操作颗味。

具體內(nèi)容

刪除配置文件的時候超陆,通常情況下通過`NSTask`這個類打開終端,輸入命令進行操作的脱衙,如:

[NSTask launchedTaskWithLaunchPath:@"/usr/bin/sudo" arguments: [NSArray arrayWithObjects:@"launchctl", @"unload", @"/Library/LaunchDaemons/com.tencent.MacScmClient.Daemon.plist",nil]];

這行代碼就是用NSTask來調(diào)用終端來進行刪除文件的侥猬,大概意思就是在終端輸入sudo,然后執(zhí)行launchctlunload的命令捐韩,但是呢退唠,怎樣寫IE肯定是不行的,為什么呢荤胁,因為你沒有權(quán)限這么做瞧预,有興趣的同學(xué)可以在終端嘗試一下,輸入這個命令是需要輸入密碼的,所以怎么獲取權(quán)限呢垢油?
之前我們的工程中有獲取授權(quán)的代碼盆驹,這個下文再說,當時同事寫了一段代碼使用AppleScript來獲取權(quán)限的滩愁,我再網(wǎng)上找了下躯喇,也找到了原文,具體的代碼如下:

Boolean runProcessAsAdministrator( NSString *scriptPath, NSArray *arguments,BOOL isAdmin, NSString **output,NSString **errorDescription)
{
   NSString * allArgs = [arguments componentsJoinedByString:@" "];
   NSString *isAdminPre = @"";
   if (isAdmin) {
    isAdminPre = @"with administrator privileges";
   }
   NSString * fullScript = [NSString stringWithFormat:@"%@ %@", scriptPath, allArgs];
   NSDictionary *errorInfo = [NSDictionary new];
   NSString *script = [NSString stringWithFormat:@"do shell script \"%@\" %@", fullScript,      isAdminPre];
   NSLog(@"script = %@",script);
   NSAppleScript *appleScript = [[NSAppleScript new] initWithSource:script];
   NSAppleEventDescriptor * eventResult = [appleScript executeAndReturnError:&errorInfo];
   // Check errorInfo/var/tmp
   if (! eventResult)
   {
       // Describe common errors
       *errorDescription = nil;
       if ([errorInfo valueForKey:NSAppleScriptErrorNumber])
       {
           NSNumber * errorNumber = (NSNumber *)[errorInfo valueForKey:NSAppleScriptErrorNumber];
           if ([errorNumber intValue] == -128)
            *errorDescription = @"The administrator password is required to do this.";
       }
       // Set error message from provided message
       if (*errorDescription == nil)
       {
           if ([errorInfo valueForKey:NSAppleScriptErrorMessage])
            *errorDescription = (NSString *)[errorInfo valueForKey:NSAppleScriptErrorMessage];
       }
       return NO;
   }
   else
   {
       // Set output to the AppleScript's output
    *output = [eventResult stringValue];
       return YES;
   }
}

這段代碼就是用AppleScript來獲取權(quán)限的硝枉,使用方法如下:

NSString *output = @"";
NSString *error= @"";
runProcessAsAdministrator(@"", [NSArray arrayWithObjects:@"launchctl", @"unload", @"/Library/LaunchAgents/com.******.******.plist",nil],false, &output, &error);

但是這么寫會有一個問題廉丽,就是我是獲得權(quán)限了,但是卸載的時候往往不可能只刪除一個配置文件妻味,而是要刪除很多個配置文件正压,起初我是這么寫的:

runProcessAsAdministrator(@"", [NSArray arrayWithObjects:@"launchctl", @"unload", @"/Library/LaunchAgents/com.******.******.plist",nil],false, &output, &error);
    NSLog(@"output = %@, error = %@", output, error);
runProcessAsAdministrator(@"", [NSArray arrayWithObjects:@"launchctl", @"unload", @"/Library/LaunchDaemons/com.******.******.Daemon.plist",nil], true, &output, &error);
    NSLog(@"output = %@, error = %@", out

我就很開心的運行,但是問題來了责球,什么問題呢焦履?就是你刪除幾個配置文件就需要輸入幾次用戶名和密碼,這樣的話用戶體驗相當?shù)牟缓贸猓硐霠顟B(tài)是什么呢嘉裤?輸入一次用戶名和密碼之后,獲取的權(quán)限以后其他的刪除配置文件的操作就不需要再次獲取權(quán)限了校套,所以我就看了下前輩們是怎么寫的价脾,大概的代碼如下:

int main(int argc, char * argv[]) {
@autoreleasepool {
    
    if (argc == 2) {
        NSLog(@"AuthHelperTool executing self-repair");
        OSStatus myStatus;
        AuthorizationFlags myFlags = kAuthorizationFlagDefaults;
        AuthorizationRef myAuthorizationRef;
        
        myStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, myFlags, &myAuthorizationRef);
        if (myStatus != errAuthorizationSuccess)
            return myStatus;
        
        AuthorizationItem myItems = {kAuthorizationRightExecute, 0, NULL, 0};
        AuthorizationRights myRights = {1, &myItems};
        myFlags = kAuthorizationFlagDefaults |
        kAuthorizationFlagInteractionAllowed |
        kAuthorizationFlagPreAuthorize |
        kAuthorizationFlagExtendRights;
        
        myStatus = AuthorizationCopyRights (myAuthorizationRef, &myRights, NULL, myFlags, NULL );
        if (myStatus != errAuthorizationSuccess)
            return myStatus;
        
        char *myToolPath = argv[1];
        char *myArguments[] = {argv[1], "--fix", NULL};
        FILE *myCommunicationsPipe = NULL;
        
        myFlags = kAuthorizationFlagDefaults;
        //這句是獲取管理員權(quán)限的代碼
        myStatus = AuthorizationExecuteWithPrivileges(myAuthorizationRef, myToolPath, myFlags, myArguments, &myCommunicationsPipe);
        return 0;

    }
    else if (argc == 3){
    
    NSString *output = @"";
    NSString *error= @"";

    runProcessAsAdministrator(@"", [NSArray arrayWithObjects:@"launchctl", @"unload", @"/Library/LaunchAgents/com.******.******.plist",nil],false, &output, &error);
    runProcessAsAdministrator(@"", [NSArray arrayWithObjects:@"launchctl", @"unload", @"/Library/LaunchDaemons/com.******.******.Daemon.plist",nil], true, &output, &error);
}

這段代碼是個可執(zhí)行文件,然后在ViewController中調(diào)用的這個可執(zhí)行文件笛匙。我們看到這個獲取權(quán)限的方法是使用Authorization的類來獲取權(quán)限的侨把,這個也是官方文檔中的獲取權(quán)限的方法,具體的可以參考這里
妹孙,繼續(xù)說上面的代碼秋柄,前文說了這個是個可執(zhí)行文件,是在ViewController中調(diào)用的蠢正,代碼如下:

NSString *helperToolPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/ExitDomain"] ;
NSLog(@"path = %@",helperToolPath);
NSArray *args = [NSArray arrayWithObjects:helperToolPath, nil];
[NSTask launchedTaskWithLaunchPath:helperToolPath arguments:args];

從這兒看到骇笔,我們是用NSTask這個類來打開終端來執(zhí)行這個可執(zhí)行文件的,參數(shù)為helperToolPath也就是這個可執(zhí)行文件的路徑嚣崭,所以到了可執(zhí)行文件的mian函數(shù)中笨触,argc就是2,然后來執(zhí)行下面的獲取權(quán)限的代碼的雹舀,下面獲取權(quán)限的代碼有個需要注意的地方:

char *myToolPath = argv[1];
        char *myArguments[] = {argv[1], "--fix", NULL};
        FILE *myCommunicationsPipe = NULL;
        
        myFlags = kAuthorizationFlagDefaults;
        //這句是獲取管理員權(quán)限的代碼
        myStatus = AuthorizationExecuteWithPrivileges(myAuthorizationRef, myToolPath, myFlags, myArguments, &myCommunicationsPipe);

這幾行代碼需要注意芦劣,首先myToolPath這個參數(shù)就是我們從ViewController中配置的那個參數(shù),也就是可執(zhí)行文件的路徑说榆,其次myArguments里面多了個--fix虚吟,這個不是命令寸认,只是為了使argc的個數(shù)變?yōu)槿?/p>

myStatus = AuthorizationExecuteWithPrivileges(myAuthorizationRef, myToolPath, myFlags, myArguments, &myCommunicationsPipe);

這行代碼就是獲取管理員權(quán)限的代碼串慰,從官方文檔來看在10.1和10.7中是不能使用的偏塞,具體的可以看官方文檔,如果想測試自己的系統(tǒng)能不能用邦鲫,請參考github上的這個第三方庫中用的測試方法灸叼,然后這行代碼還有個作用,就是它又調(diào)用了一次這個可執(zhí)行文件掂碱,方法中有個參數(shù)是myToolPath怜姿,這個就是可執(zhí)行文件的路徑,所以esle if中的代碼才會執(zhí)行疼燥,按照這種方法寫完后就只需要輸入一次用戶名和密碼,用戶體驗明顯好轉(zhuǎn)蚁堤。

總結(jié)##

本文講了兩種獲取權(quán)限的方法醉者,一種是使用`AppleScript`來獲取權(quán)限,這樣寫是能獲取到權(quán)限披诗,但是如多刪除多個文件的話撬即,就需要輸入多次用戶名和密碼;另一種是用`Authorization`這個類來獲取權(quán)限呈队,先獲取到權(quán)限后剥槐,然后再執(zhí)行刪除配置文件的操作就可以了,需要注意的地方就是宪摧,我再使用第二種方法的時候`esle if`中調(diào)用的還是`AppleScript`刪除文件的方法粒竖,沒有用`NSTask`這個類,這個說明一下几于,這兒完全可以使用`NSTask`這個類做這些事情蕊苗,也就是下面這段代碼:

runProcessAsAdministrator(@"", [NSArray arrayWithObjects:@"launchctl", @"unload", @"/Library/LaunchAgents/com.******.******.plist",nil],false, &output, &error);

完全可以用這段替換掉:

[NSTask launchedTaskWithLaunchPath:@"/usr/bin/sudo" arguments: [NSArray arrayWithObjects:@"launchctl", @"unload", @"/Library/LaunchDaemons/com.tencent.MacScmClient.Daemon.plist",nil]];

這個只是我項目中遇到的一些關(guān)于權(quán)限的問題以及解決辦法,還有很多不足之處沿彭,希望各路大神多多指正朽砰,我也會再繼續(xù)深入學(xué)習(xí),及時修改這篇文章喉刘。

參考資料

[https://developer.apple.com/search/?q=Authorization&type=Guides]
[http://stackoverflow.com/questions/29796363/how-to-add-root-privileges-to-my-osx-application]
[http://codego.net/213006/]
[http://www.tanhao.me/pieces/1279.html/]
[https://github.com/sveinbjornt/STPrivilegedTask]

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瞧柔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子睦裳,更是在濱河造成了極大的恐慌造锅,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件推沸,死亡現(xiàn)場離奇詭異备绽,居然都是意外死亡券坞,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門肺素,熙熙樓的掌柜王于貴愁眉苦臉地迎上來恨锚,“玉大人,你說我怎么就攤上這事倍靡『锪妫” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵塌西,是天一觀的道長他挎。 經(jīng)常有香客問我,道長捡需,這世上最難降的妖魔是什么办桨? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮站辉,結(jié)果婚禮上呢撞,老公的妹妹穿的比我還像新娘。我一直安慰自己饰剥,他們只是感情好殊霞,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著汰蓉,像睡著了一般绷蹲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上顾孽,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天祝钢,我揣著相機與錄音,去河邊找鬼岩齿。 笑死太颤,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的盹沈。 我是一名探鬼主播龄章,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼乞封!你這毒婦竟也來了做裙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤肃晚,失蹤者是張志新(化名)和其女友劉穎锚贱,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體关串,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡拧廊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年监徘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吧碾。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡凰盔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出倦春,到底是詐尸還是另有隱情户敬,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布睁本,位于F島的核電站尿庐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏呢堰。R本人自食惡果不足惜抄瑟,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望枉疼。 院中可真熱鬧锐借,春花似錦、人聲如沸往衷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽席舍。三九已至,卻和暖如春哮笆,著一層夾襖步出監(jiān)牢的瞬間来颤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工稠肘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留福铅,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓项阴,卻偏偏與公主長得像滑黔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子环揽,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容