app擴展,即appex,如today widget,network extension之類。現在有個需求是在開發擴展時,將log輸出到文件,在必要的時候獲取文件內容進行查看。此處不討論將log通過網絡傳輸到服務器的情況,也不討論使用類似CocoaLumberjack這樣的第三方庫的情況,我們簡單的使用NSLog而已。
-
思路整理:
- 首先,我們要能取得log文件,此處不討論通過網絡將log文件傳輸到服務器的情況。如果是普通應用,可以在xcode->devices里面通過Download container的方法,將應用數據下載到電腦上。對于擴展,雖然也有自己的沙盒,但是我并沒有找到直接將沙盒數據下載到電腦的方法。所以不考慮將log寫到擴展沙盒里面。
- 所以考慮變通的方法,將log寫到擴展和應用都能訪問到的位置,然后在應用中讀取log并轉存到應用的沙盒,這樣就可以使用xcode直接取得log。這個都能訪問到的位置是基于擴展和應用同屬于一個app group,這樣可以使用
[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:[self sharedGroupIdentifier]];
獲取到這個container目錄。 - 然后我們就只有考慮怎么將NSLog的內容寫到文件里面去了。最方便的方法是使用freopen重定向。
-
相關代碼:
- 擴展中的代碼:在擴展啟動時,獲取group container路徑,構造log文件路徑,并重定向stdout, stderr。
重定向使用"a+"模式,將log添加到文件末尾,因此多次啟動擴展Log是累積的。NSURL * containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:[self sharedGroupIdentifier]]; NSString* logFilePath = [[containerURL URLByAppendingPathComponent:@"appex.log"] path]; freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stdout); freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr);
- 應用中的代碼
NSURL * containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:[self sharedGroupIdentifier]]; NSString* appexLogFilePath = [[containerURL URLByAppendingPathComponent:@"appex.log"] path]; //讀取appex的log內容到string NSString* content = [NSString stringWithContentsOfFile:appexLogFilePath encoding:NSUTF8StringEncoding error:nil]; NSLog(@"appex log的內容是:\n%@",content); if(content.length==0){ return; } //save the log to a file in document folder //使用當前時間命名doucments中的log文件 NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd_HH-mm-ss"]; NSString *strDate = [dateFormatter stringFromDate:[NSDate date]]; NSString *docLogFileName = [NSString stringWithFormat:@"%@.appex.log", strDate]; NSString *docLogFilePath = [[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:docLogFileName]; //將content轉存到應用沙盒documents中 BOOL result = [content writeToFile:docLogFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; NSLog(@"save log to:%@ result=%d",docLogFilePath,result); if(result){ //如果成功將appex的log清空 //clear the appex log file NSString *ccc=@""; [ccc writeToFile:appexLogFilePath atomically:YES encoding:NSUTF8StringEncoding error:nil]; }
- 擴展中的代碼:在擴展啟動時,獲取group container路徑,構造log文件路徑,并重定向stdout, stderr。
這個方法簡單的進行了log的轉存,并清除了appex的log,每次調用都生成一個新的log文件放在documents里面。需要注意的是,如果log文件很大,就不能直接讀取和保存了,需要打開一個文件流,逐步讀取和保存。