Posts Tagged ‘Objective-C’

【iOS開發】發送Remote Notification給Device的二三事

Wednesday, November 13th, 2013


今天花了一些時間study了一下iOS的Push運作機制,得到以下的結論:

1. 發送iOS Push,Server端必須要記錄手機回傳的DeviceToken值,方能發送給對應的手機裝置。而這個值在同一個App(即相同的bundle id)和同一個Push憑證下,會是一個唯一的值(一串64個字元的十六進位值)。即使App砍掉,再重裝,DeviceToken也不會變。但,在不同的App環境(開發 and 正式)下,會分別得到不同的值。且不同的Push憑證也會得到不同的值(意即,如果有一天Push憑證過期了,我們不能重新上傳CSR檔去產生新的Push憑證用。否則先前所有已經存在DB裡的DeviceToken值,將全部失效。應該是renew那個Push憑證下載來用才對。)。

2. 發送Push是由Server發出一個request給Apple Push Notification service(APNs),並帶入定義好的資料格式,和額外的參數資料。並且可以有一些客制化的Notification UI調整。例如: Push的文字訊息、收到Push的音效、收到Push打開App後的預設圖片(音效和圖片必須是App裡預先放好的檔案,音效最多30秒,圖片必須滿版)、更改App Badge Number(那個紅色圓圈數字)、未開啟App時出現的Alert訊息的button文字。

3. App收到Push通知後,點開Push時。程式可以根據Server帶入的額外自訂參數,做不同的處理。例如: App收到Push通知點開時,可以跳到美食那頁,或者跳到活動頁面。基本上,App收到Push通知後,是可以做任何事的。只要預先定義好Server傳送的參數格式和Client需對應的處理動作即可。

教學文章
Apple Official Document

[Objective-C] 如何判定UIView裡的可作用區域?

Wednesday, October 31st, 2012


是這樣的,我的遊戲App裡有個地方可以讓玩家隨意放置裝備在飛機上。原本我是不打算檢查玩家放置的位置,想說讓他們自己想擺哪就擺哪,即使位置太過離普也沒關係。不過有人反應這樣似乎太過”自由”了,於是這幾天想做一些調整,讓玩家只能把裝備放在飛機上真正”看的到”的地方,而不能擺在”空氣”上。

原本是想用這種方法,也是一般遊戲裡常用的檢查物件是否碰撞的方式,利用數個rect區域來檢查。也就是在飛機圖片上設立好幾個矩形區域,用來檢查玩家放置裝備的位置是否在某個矩形區域內。但做到一半就發現,這樣實在太麻煩了。因為遊戲裡飛機的類型有好幾種,每種的圖片長像又差很多,如果要慢慢找出那些矩形區域來會很費工。而且,利用矩形去含蓋一個不規則形狀的圖片,如果矩形不夠多、不夠密,還是會有很多死角位置。玩家可能還是會不小心擺到空氣上,或者明明是應該要可以擺放的位置卻不給擺。

於是我又重新試了一個方法,將玩家擺放裝備的位置那一個像素(pixel)的顏色值抓出來做比對。由於遊戲裡的飛機圖片是透色的png 24bit圖片,所以我的方法是抓出RGBA四個顏色值,比對R, G, B, A(alpha)的值是否均為0。如果是的話,就代表玩家擺放位置是在一個透明(transparent)的像素點,那就應該要回傳NO值,告訴上層UI應該要reject這次的動作。其實也可以只比alpha值就好,不過我還是保險一點四個值全做比對。

結果就真的可以work了,不過這種檢查方法應該會比檢查矩形位置耗費的CPU資源多很多。因為要載入圖片資料,還要做一堆處理。不過,在遊戲裡只有一個頁面會需要做這種檢查,而且只有發生在玩家托曳裝備時才需要,出現的時機不會很多,所以還好。不過,使用這個方法,必須要特別注意支援Retina解析度時,檢查的位置必須乘以2,否則會錯!! 以下是我的code:

- (BOOL) checkEquipmentPosition:(CGPoint)pos {
	NSArray *arr = [ImageUtils getRGBAsFromImage:self.img atX:pos.x andY:pos.y count:1];
	UIColor *color = arr[0];

	CGFloat r = 0.0f;
	CGFloat g = 0.0f;
	CGFloat b = 0.0f;
	CGFloat a = 0.0f;
	[color getRed:&r green:&g blue:&b alpha:&a];

	BOOL result = YES;
	log(@"########### color: (%f, %f, %f, %f)", r, g, b, a);
	if( r == 0.0f && g == 0.0f && b == 0.0f && a == 0.0f ) {
		result = NO;
	}
	return result;
}

+ (NSArray*)getRGBAsFromImage:(UIImage*)image atX:(int)xx andY:(int)yy count:(int)count
{
    NSMutableArray *result = [NSMutableArray arrayWithCapacity:count];

    // First get the image into your data buffer
    CGImageRef imageRef = [image CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(rawData, width, height,
                    bitsPerComponent, bytesPerRow, colorSpace,
                    kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);

    // Now your rawData contains the image data in the RGBA8888 pixel format.
    int byteIndex = (bytesPerRow * yy) + xx * bytesPerPixel;
    for (int ii = 0 ; ii < count ; ++ii)
    {
        CGFloat red   = (rawData[byteIndex]     * 1.0) / 255.0;
        CGFloat green = (rawData[byteIndex + 1] * 1.0) / 255.0;
        CGFloat blue  = (rawData[byteIndex + 2] * 1.0) / 255.0;
        CGFloat alpha = (rawData[byteIndex + 3] * 1.0) / 255.0;
        byteIndex += 4;

        UIColor *acolor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
        [result addObject:acolor];
    }

  free(rawData);

  return result;
}

抓取像素顏色資料的util function原文:
http://stackoverflow.com/questions/448125/how-to-get-pixel-data-from-a-uiimage-cocoa-touch-or-cgimage-core-graphics

如何在Objective-C中宣告一個 private function?

Sunday, September 2nd, 2012

這是一個很簡單很基本的問題,寫過Java或C++的人都知道怎麼寫
不過,Objective-C居然沒有支援,這讓我從兩年前開始學Objective-C時就覺得很納悶
我也沒有特別去找有沒有什麼方法可以做到,今天在看cocos2d的書時剛好有講到,寫下來免得忘記

方法就是在 .m 檔裡的 @implementation 之前另外加入 @interface 的宣告 (一般而言 @interface 都是在 .h 裡做)
例:

#import “MyClass.h”
@interface MyClass()
- (void) doMyPrivateFunction;
- (int) getMyMagicNumber;
@end

@implementation MyClass
….. (略)
@end