Skip to content

Instantly share code, notes, and snippets.

@JacksonTian
Last active April 19, 2018 07:58
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save JacksonTian/5855751 to your computer and use it in GitHub Desktop.
Save JacksonTian/5855751 to your computer and use it in GitHub Desktop.
iOS应用开发技能点

图标上的数字

application.applicationIconBadgeNumber = N; // 设为0隐藏图标数字

从应用打开另一个网页

// 从应用打开一个网页
NSString *url = @"http://tadu.com";
[application openURL:[NSURL URLWithString:url]];

POST一段数据到客户端

// Save the token to server
NSString *urlStr = [NSString stringWithFormat:@"https://%@/push_token", @"tdpush.ap01.aws.af.cm"];
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];

[req setHTTPMethod:@"POST"];
[req setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-type"];
NSMutableData *postBody = [NSMutableData data];
[postBody appendData:[[NSString stringWithFormat:@"username=%@", @"JacksonTian"]
                      dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[[NSString stringWithFormat:@"&token=%@",
                       pushToken] dataUsingEncoding:NSUTF8StringEncoding]];

[req setHTTPBody:postBody];
NSURLConnection *conn = [[NSURLConnection alloc] init];
(void)[conn initWithRequest:req delegate:nil];

向用户请求发送通知

[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];

接收用户对通知的选择

用户确认接收:

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
    NSString *tokenStr = [deviceToken description];
    NSString *pushToken = [[[tokenStr stringByReplacingOccurrencesOfString:@"<" withString:@""]
                            stringByReplacingOccurrencesOfString:@">" withString:@""]
                            stringByReplacingOccurrencesOfString:@" " withString:@""];
}

接收到token后,需要将数据提交到服务端,服务端才能通过APNS向用户设备发送通知。 用户拒绝接收:

- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error
{
    NSLog(@"Failed to get token, error: %@", error);
}

用户通过通知打开应用,检查lanchOptions

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    if (launchOptions != nil)
    {
		NSDictionary *dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
		if (dictionary != nil)
		{
			NSLog(@"Launched from push notification: %@", dictionary);
		}
	}

    return YES;
}

用户收到通知,从通知重新打开应用:

- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
{
    NSLog(@"Received notification: %@", userInfo);
}

本地通知

设定一个时间发出通知。本地通知只在应用在后台运行时才会出现

UILocalNotification *notification = [[UILocalNotification alloc] init];
if (notification!=nil) {
    NSLog(@">> support local notification");
    notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:10];
    notification.timeZone = [NSTimeZone defaultTimeZone];
    notification.alertBody = @"该去吃晚饭了!";
    [[UIApplication sharedApplication] scheduleLocalNotification:notification];
}

从本地通知打开应用时

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
    NSLog(@"收到本地通知");
}

取消已有的本地通知

[[UIApplication sharedApplication] cancelAllLocalNotifications];

网络编程篇

发送GET请求

NSURL *url = [NSURL URLWithString:@"http://www.google.com/"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];

NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];

接收GET请求的数据

在创建Connection建立的时候传递请求对象和委托对象。委托对象需要实现NSURLConnectionDataDelegate协议。具体方法如下:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;

didReceiveResponse在响应开始时触发。didReceiveData在收到数据包时触发。connectionDidFinishLoading在响应结束后触发。 接收数据时要在didReceiveResponse中准备接收数据的容器,在didReceiveData中将数据块装入容器,在connectionDidFinishLoading中整个倒出来使用。

HTTPS证书问题

一般而言HTTP和HTTPS都不会遇到这个问题,只要实现NSURLConnectionDataDelegate协议就能完成需求。但是对于自签名证书,NSURLConnection对象无法验证服务端证书的真伪。这个时候需要动用到NSURLConnectionDelegate协议。

具体方法是以下几个:

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)prote
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;

其中canAuthenticateAgainstProtectionSpace如果返回No,将由系统自行处理。返回YES将会由后续的didReceiveAuthenticationChallenge处理。默认为No。

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
    NSLog(@"处理证书");
    return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}

didReceiveAuthenticationChallenge中我们要通过challengesender告知是否信任服务端的证书。

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    if (trusted) {
        [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
    } else {
        [challenge.sender cancelAuthenticationChallenge:challenge];
    }
}

我们可以设定trusted来判定是否信任。可以直接设置为YES来表示信任服务端。但是直接设置是不严谨的,并没有验证服务端证书的真伪。

验证证书

在连接建立后,我们可以拿到服务端的证书。要验证它的真伪需要我们用CA的证书来进行判定。

// 获取der格式CA证书路径
NSString *certPath = [[NSBundle mainBundle] pathForResource:@"ca" ofType:@"der"];
// 提取二进制内容
NSData *derCA = [NSData dataWithContentsOfFile:certPath];

// 根据二进制内容提取证书信息
SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)derCA);
// 形成钥匙链
NSArray * chain = [NSArray arrayWithObject:(__bridge id)(caRef)];

caChainArrayRef = CFBridgingRetain(chain);

// 取出服务器证书
SecTrustRef trust = [[challenge protectionSpace] serverTrust];

SecTrustResultType trustResult = 0;
// 设置为我们自有的CA证书钥匙连
int err = SecTrustSetAnchorCertificates(trust, caChainArrayRef);
if (err == noErr) {
    // 用CA证书验证服务器证书
    err = SecTrustEvaluate(trust, &trustResult);
}
CFRelease(trust);
// 检查结果
BOOL trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed)||(trustResult == kSecTrustResultConfirm) || (trustResult == kSecTrustResultUnspecified));

UIWebView中访问HTTPS

UIWebView不能处理自签名的证书,需要在它发起访问之前通过上述的方法进行证书的设置判定,之后再通过UIWebView进行访问即可通过。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment