2014年9月30日 星期二

iOS 8 Location 定位 失效

一,先在Info.plist加入這二個Key(value是string,你可以不加,也可以加上Location is required to find out where you are之類的文字
NSLocationAlwaysUsageDescription
NSLocationWhenInUseUsageDescription

二,在啟用location update之前加入這段,來要求權限
// Check for iOS 8. Without this guard the code will crash with "unknown selector" on iOS 7.
        if ([_locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
//要求權限:前景背景都允許使用定位
            [_locationManager requestAlwaysAuthorization];
        }
        if ([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
//要求權限:只有在前景允許使用定位
            [_locationManager requestWhenInUseAuthorization];

        }

取得iAP的receipt

//取得iAPreceipt
+(NSData *) getReceiptData:(SKPaymentTransaction *)transaction{
    NSData *receiptData = nil;
    if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
        receiptData = transaction.transactionReceipt;
    }
    else {
        NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[[NSBundle mainBundle] appStoreReceiptURL]];
        NSError *error = nil;
        receiptData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:&error];
    }
    return receiptData;

}

2014年9月29日 星期一

UUID保存在KeyChain裡面

用這個方式將第一次取得的Vender UUID存到KeyChain內,
之後換新App就可以取得之前UUID來充當UDID使用。

https://github.com/ObjColumnist/MCSMKeychainItem

單獨reload一個section

[tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationNone];

2014年9月25日 星期四

navigationController在push新view前,把tabBar隱藏起來

有時候我們會想要用navigation bar來push一個新的view,但又不想要下面看到原本的tab bar,但限於navigation controller在 tabbar controller的階層下。又不想用present modal view的方式破壞原本的結構。

這時候我們可以在push前把tab bar隱藏起來,在pop的時候記得要解開隱藏。
程式碼:
        AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
        appDelegate.rootTabBarController.tabBar.hidden = YES;

        [self.navViewController pushViewController:main animated:YES];

2014年9月24日 星期三

繼承自managed object的class不能用object method存取

因為xcode中自動產生的managed object,很容易因為修改db,而重新產生,
所以習慣上,我會再寫一個managed object去繼承自動生成的來使用,
然而今天發現用自己寫的class創建object仍然會被視為自動產生的那個class,造成object method無法被呼叫而發出例外。

解決方式有兩種:
一種是把object method寫進自動生成的managed object,但降子就背離了原來用繼承的原意,所以我採用第二種。
第二種是把object method全部寫成class method。

2014年9月22日 星期一

[轉錄]plist解說

本文轉錄自
http://iphone4.tw/forums/showthread.php?t=195508
kes729的文章

1. Application does not run in background(鍵名:UIApplicationExistsOnSuspend)自從iOS4.0之後,當你在應用程式執行的時候按下Home鍵,應用程式並不會中斷目前的執行,而是躲到背景去了。因此希望使用者在按下Home鍵之後就要中斷目前程式的執行,請勾選這個選項。

2. Application requires iPhone environment(鍵名:LSRequiresIPhoneOS)iOS的家族繫***ㄧ誒主要包含了iPhoneiPadiPod Touch這三種設備。因此如果你的應用程式只能在iPhone環境下使用的話,請勾選這選項。

3. Application supports iTunes file sharing(鍵名:UIFileSharingEnabled)iTunes9.1之後的版本增加了一個檔案共享的功能,只要打開info.plist裡面的這個選項,然後把你要共享的檔案儲存在Documents目錄裡面,就可以在iTunes裡面的應用程式標籤頁看到這份文件。

4. Application uses Wi-Fi(鍵名:UIRequiresPersistentWiFi)如果你的應用程式需要使用的WiFi來連線的話,那麼你可以開啓這個功能。當使用者在執行這個應用程式的時候並未開啓WiFi,那麼在畫面上會自動跳出對話框要求開啓WiFi

5. Bundle creator OS Type code (鍵名:CFBundleSignature)CFBundleSignature是一個四個字母長度的字串,用以表示開發者對於應用程式的標識。例如:在一個文字編輯的應用程式,你可以標識為”ttext”

6. Bundle display name(鍵名:CFBundleDisplayName)應用程式本土化的顯示名稱,預設值為${PRODUCT_NAME}。這個變數可以在雙敲擊Targets後出現的專案設定畫面中修改,找到”Product Name”後修改為你的產品名稱就可以了,編譯後的.app也會以這個名稱命名。

7. Bundle identifier(鍵名:CFBundleIdentifier)用來標示應用程式的唯一ID,通常是以反向的DNS方式命名的,例如:com.myCompany.myApp,這個名稱應該在iTunes Connect裡面新增的應用程式ID一致。

8. Bundle name(鍵名:CFBundleName)應用程式的短名稱,通常就是你的應用程式名稱。

9. Bundle OS Type code(鍵名:CFBundlePackageType)用來標識整個封包的(bundle)的類型。在Mac裡面,一個封包可能是一個檔案或目錄,其目的在於將軟體使用到的資源包在一起。例如應用程式應標識為APPL

10. Bundle version(鍵名:CFBundleVersion)用以標識編譯版本(Bundle number),你可以使用任何字串格式來表示這個版本。例如使用一個數字來表示編譯次數。

11. Bundle version string,short (鍵名:CFBundleShortVersionString)應用程式的版本,通常是以三個數字來表示版本號,例如:1.0.1

12. Executable architectures(鍵名:LSExcutableArchitectures)為一個陣列形態的設定值。用以設*****绦袚蹩梢赃\行的架構環境,例如:i386ppcppc64x86_64

13. Executable file(鍵名:CFBundleExecutable)執行檔的名稱。

14. Fonts provide by application(鍵名:UIAppFonts)為一個陣列形態的設定值。用來指定應用程式所使用的外部字型。你可以在應用程式內使用自己的字型檔,只要將字型檔案加入到專案內,在設定值指定字型檔名稱就可以在程式碼裡面使用到這些字型了。

15. Get Info string (鍵名:CFBundleGetInfoString)用於MacFinder上的應用程式的描述。

16. Icon already includes gloss effects(鍵名:UIPrerenderedIcon)指定應用程式的圖示是否加上光暈效果,如果不希望加上光暈效果,那麼勾選此選項。

17. Icon file(鍵名:CFBundleIconFile)用來設定應用程式的圖示檔,如果沒有指定的話,則使用預設值Default.png,依照Apple的規定,這個圖是必須是57x57的圖形檔。

18. Icon files(鍵名:CFBundleIconFiles)由於iPhoneiPad的開發工具以及SDK都是相同的,因此同一個應用程式也可以同時在兩個設備上使用,只不過兩著的圖是不太一樣。這個鍵值是一個陣列類型的設定值,用來指定iPhoneiPad的應用程式圖示,你只要給兩個圖示檔名,其中iPhone的圖示為57x57 pixeliPad則為72x72 pixel,系統會自動依照圖示大小判斷該圖示是使用在哪種設備上。

19. Info dictionary version(鍵名:CFBundleInfoDictionaryVersion)info.plist格式的版本。一般來說,我們不會變動這個數值。

20. Initial interface orientateon(鍵名:UIInterfaceOrientation)指定應用程式初始時的方向。

21. Laumch image(鍵名:UILaunchImageFile)用以指定應用程式啓動時的圖檔。

22. Localization native development region(鍵名:CFBundleDevelopmentRegion)應用程式原始的語系版本。

23. Localizations(鍵名:CFBundleLocalizations)用以指定應用程式所支援的語系。

24. Localized resources can be mixed(鍵名:CFBundleAllowedMimxedLocalizations)是否允許應用程式可以取得框架庫內的語系檔。

25. Main nib file base name(鍵名:NSMainNibFile)主要的Nib檔案名稱,預設值為MainWindow

26. Renders with edge antialisasing(鍵名:UIViewEdgeAntialiasing)設定core animation的圖層是否開啓抗鋸齒功能。

27. Renders with group opacity(鍵名:UIViewGroupOpacity)設定core animation的圖層使否繼承上一層透明度。

28. Required background modes(鍵名:UIBackgroundModes)設定當應用程式進入背景執行後,哪些動作要繼續在背景執行。這個鍵值是一個陣列類型的設定,可設定動作包括:audiolocateonvoip

29. Required device capabilities(鍵名:UIRequiredDeviceCapabilities)設定應用程式需要使用到的硬體,如此可以確定應用程式在該設備上執行時不會發生錯誤。

30. Status bar is initially hidden(鍵名:UIStatusBarHidden)設定狀態列是否一開始隱藏。

31. Status bar style(UIStatusBarStyle)設定狀態列的顯示類型。

32. Supported external accessory protocols(鍵名:UISupportedExternalAccessoryProtocols)指定應用程式與外界硬體配件間支援的通訊協定,這個鍵值是一個陣列設定,可以指定多個通訊協定。

33. Supported interface orientateons(鍵名:UISupportedInterfaceOrientations)設定應用程式所支援的顯示模式(肖像模式或風景模式),這個鍵值是一個陣列,可以支援多個不同的顯示模式。

34. Supported interface orientateons(鍵名:UIUpgradeOtherBundleIdentifier)設定應用程式所支援的顯示模式(肖像或是風景模式),這個鍵值可以支援多個不同的顯示模式。

2014年9月18日 星期四

用Binary保存NSArray

//讀取
NSMutableArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:anEntity.arrayProperty];

//儲存
NSData *arrayData = [NSKeyedArchiver archivedDataWithRootObject:TheArray]; myEntity.arrayProperty = arrayData; [self saveContext];

2014年9月17日 星期三

二選一註解方式

我們常會遇到需要測試的方法,可以降子使用註解:
一,呼叫method1
                //*測試用
                [self method1];
                /*///正式用
                [self method2];
                //*/
二,呼叫method2
                /*測試用
                [self method1];
                /*///正式用
                [self method2];
                //*/

把NSArray直接寫入plist

NSString* areaRootPath = [[FolderHelper share] areaFolderRootPath];
    NSString* areaPlistPath = [areaRootPath stringByAppendingPathComponent:kKeyFile_CourseAreaList];

//直接把array(裡面包dictionary)寫入plist
[plistMAry writeToFile:areaPlistPath atomically:true];

2014年9月15日 星期一

NSKeyedArchiver保存文件

    //=================NSKeyedArchiver========================
    NSString *saveStr1 =@"This is";
    NSString *saveStr2 =@"Data";
    NSArray *array = [NSArray arrayWithObjects:saveStr1, saveStr2, nil];
    //----Save
    //合成完整路徑
    NSString *Path =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0];
    NSString *filename = [Path stringByAppendingPathComponent:@"saveDatatest"];
    [NSKeyedArchiver archiveRootObject:array toFile:filename];
    //----Load

    array = [NSKeyedUnarchiver unarchiveObjectWithFile: filename];

2014年9月11日 星期四

2014年9月10日 星期三

抓取系統目前使用語系

NSString* usedLanguage = [[NSLocale preferredLanguages] objectAtIndex:0];
    
    if([usedLanguage isEqualToString:@"zh-Hant"]) //中文 不分地區
{
//TODO:中文
}
else if([usedLanguage isEqualToString:@"ja"])
{
//TODO:日文
}
 else
 {
     //TODO:其他語系

 }

使用Reachability判斷目前網路狀態

-(BOOL)connectedToNetworkWithShowAlert:(BOOL)ShowAlert
{
    BOOL result = true;
    Reachability *r = [Reachability reachabilityWithHostName:@"www.apple.com"];
    switch ([r currentReachabilityStatus]) {
        default:
        case NotReachable:
            // 沒有網路
            result = false;
            break;
        case ReachableViaWWAN:
            // 使用3G網路
            break;
        case ReachableViaWiFi:
            // 使用WiFi網路
            break;
    }
    
    if(!result && ShowAlert)
    {
        UIAlertView* alertView = [[UIAlertView alloc]
                                  initWithTitle:nil
                                  message:NSLocalizedString(@"HaveNotInternet", @"HaveNotInternet")
                                  delegate:nil
                                  cancelButtonTitle:NSLocalizedString(@"yes", @"yes")
                                  otherButtonTitles:nil];
        
        [alertView show];
    }
    
    return result;

}

2014年9月9日 星期二

好用的遠端推播測試 NWPusher

https://github.com/noodlewerk/NWPusher

執行之後你只需輸入device token id即可,他會幫你抓到你申請好的.p12的金鑰檔案,就可以發送遠端推播到你要測試的App

無聲推播(Silent Push Notification)

  • 先在你的.plist中加入Required background modes,再把item設定為App downloads content in response to push notifications

  • 在appDelegate.m中實作下面的function(只有iOS7.0以上才有),這個function會在顯示之前被呼叫。
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))handler{    //Success    handler(UIBackgroundFetchResultNewData);
    • 在appDelegate的didFinishLaunchingWithOptions中註冊通知。

    // register for types of remote notifications
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeNewsstandContentAvailability|
     UIRemoteNotificationTypeBadge |
     UIRemoteNotificationTypeSound |
     UIRemoteNotificationTypeAlert)];


    Server推送的資料格式
    有聲推播的資料格式:{"aps":{"alert":"Testing.. (9)","badge":1,"sound":"default"}}
    無聲推播的資料格式:{"aps":{"content-available":1,"sound":"","say":"hello"}}
        其中,"content-avilable":1就是無聲推播的關鍵key。

    收到無聲推播之後,你可以把無聲推播的userInfo放在Local推播中再發出去,降子你可以在didReceiveLocalNotification中收到資訊。

    UUID

    目前iOS只提供二種UUID給developer分辨,

    idfa

    • 全名:advertisingIdentifier
    •   #import <AdSupport/AdSupport.h>
      
        NSString *adId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
    • 可以被使用者在settings中關掉

    idfv

    • 全名:identifierForVendor
      NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    
    
    • 不可以被關掉,但他是綁定你Bundle ID的前面二個單字 com.harvey,所以如果使用者的手機中所有你的Bundle ID的App都被刪掉,那他再次安裝這支App時,idfv就會換掉。
    可以利用KeyChain保存UUID來當作UDID來使用
    http://www.cnblogs.com/smileEvday/p/UDID.html
    
    
    另外還可以用Notification token ID,它在你重灌App後仍能保持一致,但如果系統重新更新就被換掉。

    「轉載」APNs證書過期

    「轉載自http://www.tuicool.com/articles/yiqmEr」

    開發狀態服務器地址 gateway.sandbox.push.apple.com 2195

    產品狀態服務器地址 gateway.push.apple.com         2195
    Development和Production兩個版本對應的apns device token是不同的 ,前者是develop的 mobileprovision下獲取的。後者是production的mobileprovision獲取的。
    Development和Production兩個版本 可以共用一個App ID ( 不推薦 。共用時每次調試前都要刪除設備上的app,重新打包生成。而且公用appid會經常抓狂,早上行,下午就不行了。所以不推薦),但是 不能 共 用一個mobileprovision ,所以要單獨生成Distribution的證書供production版本使用。
    注:Distribution的版本是無法在設備上debug調試的!
    Development和Production兩個版本的code sign是不同的,前者是 iPhone Developer,後者是iPhone Distribution。注意不能搞錯。

    無論是Development Push SSLCertificate還是Production Push SSL Certificate 都有過期時間的。 Development Push SSL Certificate 有效期大概 四個月 左右,而 ProductionPush SSL Certificate 的有效期是 一年 。需要注意在過期之前生成新的證書,以免影響使用。
    openssl pkcs12 -clcerts -nokeys -out apns-dev-cert.pem -in apns-dev-cert.p12
    openssl pkcs12 -nocerts -out apns-dev-key.pem -in apns-dev-cert.p12
    openssl rsa -in apns-dev-key.pem -out apns-dev-key-noenc.pem
    cat apns-dev-cert.pem apns-dev-key-noenc.pem > apns-dev.pem 在Mac上生成 Apple推送通知SSL許可證:
        1.    登錄到 iPhone Developer Connection Portal 並點擊 App IDs
        2.    創建一個不使用星號的 App ID 。星號 ID 不能用於推送通知服務。例如,我們的iPhone程序ID像這樣:  AB123346CD.com.serverdensity.iphone
        3.    點擊App ID旁的“Configure”,然後按下按鈕生產 推送通知許可證。根據“向導”指導的步驟生成一個簽名並上傳,最後下載生成的許可證。此步驟在 Apple文檔中 也有談到。
        4.    通過雙擊.cer文件將你的 aps_developer_identity.cer 引入Keychain中。
        5.    在Mac上啟動 Keychain助手,然後在login keychain中選擇 Certificates分類。你將看到一個可擴展選項“Apple Development Push Services”
        6.    擴展此選項然後右擊“Apple Development Push Services” > Export “Apple Development Push Services ID123”。保存為 apns-dev-cert.p12 文件。
        7.    擴展“Apple Development Push Services” 對“Private Key”做同樣操作,保存為 apns-dev-key.p12 文件。
        8.    需要通過終端命令將這些文件轉換為PEM格式:
    openssl pkcs12 -clcerts -nokeys -out apns-dev-cert.pem -in apns-dev-cert.p12
        9.    轉換得到key的pem:
    openssl pkcs12 -nocerts -out apns-dev-key.pem -in apns-dev-cert.p12
        10.    如果你想要移除密碼,要麼在導出/轉換時不要設定或者執行:
    openssl rsa -in apns-dev-key.pem -out apns-dev-key-noenc.pem
        11.    最後,你需要將鍵和許可文件合成為apns-dev.pem文件,此文件在連接到APNS時需要使用:
    cat apns-dev-cert.pem apns-dev-key-noenc.pem > apns-dev.pem

    將此文件保存為一個易記的名字,你有可能以後會用到它。上述步驟同樣適合於生成產品許可證。

    檢驗證書是否正確的方法:

    $ telnet gateway.sandbox.push.apple.com 2195

    Trying 17.172.232.226…

    Connected to gateway.sandbox.push-apple.com.akadns.net.

    Escape character is ‘^]’.

    它將嘗試發送一個規則的,不加密的連接到 APNS 服務。如果你看到上面的反饋,那說明你的MAC能夠到達 APNS 。按下Ctrl+C 關閉連接。如果得到一個錯誤信息,那麼你需要確保你的防火牆允許2195端口。

    然後再次連接,這次用我們的SSL證書和私鑰來設置一個安全的連接:

    $ openssl s_client -connect gateway.sandbox.push.apple.com:2195

    -cert PushChatCert.pem -key PushChatKey.pem

    Enter pass phrase for PushChatKey.pem:

    你會看到一個完整的輸出,讓你明白OpenSSL在後台

    當然上面要測試prodution版本是否正確的話,把 gateway.sandbox.push.apple.com換成 gateway.push.apple.com就好。

    客戶端很好做,申請證書,復制代碼,就行了。
    服務器端, 如果是php的,那必須使用.pem的證書,如果是java的,那必須使用.p12的證書 。(很可能還需要雙擊證書進行安裝!)
    服務器端發出的 json包是有大小限制的,最大256字節 ,包括自定義字典集。
    aps中的alert字符串裡是可以添加"\n"做換行的。
    json包中除了alert,badge,sound之外,還是是可以自定值的。

    額外的自定義值:
    $payload['aps'] = array('alert' => 'This is the alert text', 'badge' => 1, 'sound' => 'default');
    $payload['server'] = array('serverId' => $serverId, 'name' => $name);
    $output = json_encode($payload);
    當用戶按下“View”後,自定義server值將被傳遞到設備中的程序。JSON 值如下:
    {
    "aps" :


              { "alert" :
                          {
                            "action-loc-key" : "顯示" ,
                            "body" : "This is the alert text"
                           },
                 "badge" : 1,
                 "sound" : "default" },
    "server" : { "serverId" : 1, "name" : "Server name")
    }
    256字節的限制適用於整個payload,包括自定義字典集。

    原生接口
    在Server Density中,一旦產生了一條提示,將建立一個payload並插入隊列中。因此有必要時我們可以同時發送多個payload。
    Apple推薦使用這種方法,因為如果你在發送各payload時頻繁連接和斷開, APNS 有可能會封鎖你的IP。
    如Apple 描述:
    原生接口使用原生socket,具有二進制內容,采用數據流技術,不產生回饋。

    高人的總結: APPLE推送通知服務教程 PART-1
    APPLE推送通知服務教程 PART-2
    APPLE推送通知服務教程 PART-3
    apns php版本:
    https://code.google.com/p/apns-php/wiki/CertificateCreation
    生成證書需要注意事項:
    蘋果開發者賬號分好幾種角色
    Agent:代理人,擁有最高權限,可以訪問iTunes Connect。
    Admin:管理員,擁有管理成員、維護設備列表,維護APPID以及證書列表權限。
    Member:普通成員,只讀權限。

    備注:3013.9.11經過測試,我發現前段時間蘋果網站下線期間更新了證書生成機制。以前,利用鑰匙串生成一個CSR文件,可以一直用。但是,現在每 當你要生成證書,做generate的時候都需要提前重新生成一個CSR文件,否則你生成的證書都是無效的,假證書,尤其是PUSH的,服務端使用這種證 書根本無法和APNS建立連接,這種詭異的問題超難跟蹤的!希望看到這段話的人都能避免走彎路,不用謝了!