iOS上架全流程及IPV6问题

Home / iOS 百晓生 2018-8-17 6397

1.iOS公司账号($99)/企业账号($299)申请

2.iOS App上架流程(2016详细版)

上面2个主要是说明证书申请和打包上传及审核流程,本文主要内容是解决app store上架的排名第三问题(据说是上架问题排行榜第三,也不知道是不是真的,姑且就当作是真的呗)。

如果项目中仅使用了http或https协议,那只需要把ip地址用域名就行了,另外尽量用nssession之类系统提供的api,毕竟iOS系统自己肯定是支持ipv6的(好像很多做iOS开发的都喜欢用第三方http库,个人觉得这么简单的东西,也没啥必要)。简单封装一下就可以了。

typedef void (^HttpHandler)(NSData* _Nullable data, NSURLResponse* _Nullable res, NSError* _Nullable e);
+ (void) httpAsAsynchronousRequestUrl:(NSString *)spec post:(NSString *)data httpHandler:(HttpHandler)handler {
    NSURL *url = [NSURL URLWithString:spec];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    if(data != nil){
        request.HTTPMethod = @"POST";
        request.HTTPBody = [data dataUsingEncoding:NSUTF8StringEncoding];
    }else{
        request.HTTPMethod = @"GET";
    }
    [request setTimeoutInterval:15];
    //application/json
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    //NSLog(@"%@",spec);
    NSURLSession *session = [NSURLSession sharedSession];
    // 由于要先对request先行处理,我们通过request初始化task
    NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:handler];
    [task resume];
}
+ (NSData*) httpAsSynchronousRequestUrl:(NSString *)spec post:(NSString* _Nullable)data {
    NSURL *url = [NSURL URLWithString:spec];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    if(data != nil){
        request.HTTPMethod = @"POST";
        request.HTTPBody = [data dataUsingEncoding:NSUTF8StringEncoding];
    }else{
        request.HTTPMethod = @"GET";
    }
    //application/json
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    //NSLog(@"%@",spec);
    //NSURLSession *session = [NSURLSession sharedSession];
    NSData* response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    return response;
}

一个同步&异步2个方法

如果项目中不仅有http(https)协议,还有socket,也是需要做ipv6的支持的

下面是oc代码

//获取不同网络环境的IP地址
+ (NSString *)getSockAddrIPString:(const struct sockaddr *)sa;
//根据不同的网络环境设置端口
+ (void)setPort:(uint16_t)port forSockAddr:(const struct sockaddr *)sa;
@end
@implementation IPv6Tester
+ (NSString *)getSockAddrIPString:(const struct sockaddr *)sa 
{
	NSString *result = @"";
	sa_family_t netType = sa->sa_family;
	if(netType == AF_INET) 
	{
		char ipv4_str_buf[INET_ADDRSTRLEN] = {0};
		struct sockaddr_in *v4sa = (struct sockaddr_in *)sa;
		inet_ntop(AF_INET,//
		&(v4sa->sin_addr),//
		ipv4_str_buf,//
		sizeof(ipv4_str_buf));
		result = [[NSString alloc] initWithCString:ipv4_str_buf encoding:NSUTF8StringEncoding];
	} else if(netType == AF_INET6) 
	{
		char ipv6_str_buf[INET6_ADDRSTRLEN] = {0};
		struct sockaddr_in6 *v6sa = (struct sockaddr_in6 *)sa;
		inet_ntop(AF_INET6,//
		&(v6sa->sin6_addr),//
		ipv6_str_buf,//
		sizeof(ipv6_str_buf));
		result = [[NSString alloc] initWithCString:ipv6_str_buf encoding:NSUTF8StringEncoding];
	}
	return result;
}
+ (void)setPort:(uint16_t)port forSockAddr:(const struct sockaddr *)sa 
{
	sa_family_t netType = sa->sa_family;
	if(netType == AF_INET) 
	{
		struct sockaddr_in *v4sa = (struct sockaddr_in *)sa;
		v4sa->sin_port = htons(port);
	} else if(netType == AF_INET6) 
	{
		struct sockaddr_in6 *v6sa = (struct sockaddr_in6 *)sa;
		v6sa->sin6_port = htons(port);
	}
}
+ (void)testMain 
{
	struct addrinfo res0;
	struct addrinfo *res1 = 0;
	struct addrinfo *res2 = 0;
	const char *cause = 0;
	//这里更换成你的服务器ip地址
	const char *address = "xxx.xx.xx.xxx";
	//这里是服务端口
	NSUInteger port = 8084;
	memset(&res0, 0, sizeof(res0));
	res0.ai_family = PF_UNSPEC;
	res0.ai_socktype = SOCK_STREAM;
	res0.ai_flags = AI_DEFAULT;
	int error = getaddrinfo(address, NULL, &res0, &res1);
	if (error) 
	{
		//没有连接上
		errx(1, "%s", gai_strerror(error));
	}
	int s = -1;
	for (res2 = res1; res2; res2 = res2->ai_next) 
	{
		s = socket(res2->ai_family,
		res2->ai_socktype,
		res2->ai_protocol);
		if (s < 0) 
		{
			cause = "socket";
			continue;
		}
		struct sockaddr *addr = (struct sockaddr *)res2->ai_addr;
		[TestIPV6 setPort:(uint16_t)port forSockAddr:addr];
		NSString *ipString = [TestIPV6 getSockAddrIPString:addr];
		NSLog(@"尝试连接地址 : %@", ipString);
		if (connect(s, res2->ai_addr, res2->ai_addrlen) < 0) 
		{
			cause = "connect";
			close(s);
			s = -1;
			continue;
		}
		break;
	}
	if(s >= 0) 
	{
		UIAlertView *alertview = [[UIAlertView alloc]
		initWithTitle:@"提示"
		message:@"连接成功"
		delegate:self
		cancelButtonTitle:@"取消"
		otherButtonTitles:@"好的", nil];
		[alertview show];
	} else 
	{
		//没有连接上
		UIAlertView *alertview = [[UIAlertView alloc]
		initWithTitle:@"提示"
		message:@"连接失败"
		delegate:self
		cancelButtonTitle:@"取消"
		otherButtonTitles:@"好的", nil];
		[alertview show];
		err(1, "%s", cause);
	}
	freeaddrinfo(res1);
}
@end

如果纯C环境稍微改装下

#ifndef IPV6_h
#define IPV6_h
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <err.h>
#include <string.h>
static std::string getSockAddrIPString(const struct sockaddr * sa)
{
    std::string result;
    sa_family_t netType = sa->sa_family;
    if(netType == AF_INET)
    {
        char ipv4_str_buf[INET_ADDRSTRLEN] = {0};
        struct sockaddr_in *v4sa = (struct sockaddr_in *)sa;
        
        inet_ntop(AF_INET,//
                  &(v4sa->sin_addr),//
                  ipv4_str_buf,//
                  sizeof(ipv4_str_buf));
        
        result = ipv4_str_buf;
    }
    else if(netType == AF_INET6)
    {
        char ipv6_str_buf[INET6_ADDRSTRLEN] = {0};
        struct sockaddr_in6 *v6sa = (struct sockaddr_in6 *)sa;
        
        inet_ntop(AF_INET6,//
                  &(v6sa->sin6_addr),//
                  ipv6_str_buf,//
                  sizeof(ipv6_str_buf));
        
        result = ipv6_str_buf;
    }
    return result;
}
static void setPort(int port,const struct sockaddr * sa)
{
    sa_family_t netType = sa->sa_family;
    if(netType == AF_INET)
    {
        struct sockaddr_in *v4sa = (struct sockaddr_in *)sa;
        v4sa->sin_port = htons(port);
    }
    else if(netType == AF_INET6)
    {
        struct sockaddr_in6 *v6sa = (struct sockaddr_in6 *)sa;
        v6sa->sin6_port = htons(port);
    }
}
static std::string convertServerAddr(const char* cpIpAddr,int nPort)
{
    std::string server;
    if(strcmp(cpIpAddr,"0.0.0.0") == 0)return std::string("0.0.0.0");//过滤无效的ip地址
    
    struct addrinfo res0;
    struct addrinfo *res1 = 0;
    struct addrinfo *res2 = 0;
    
    memset(&res0, 0, sizeof(res0));
    res0.ai_family = PF_UNSPEC;
    res0.ai_socktype = SOCK_STREAM;
    res0.ai_flags = AI_DEFAULT;
    
    int error = getaddrinfo(cpIpAddr, NULL, &res0, &res1);
    if (error)
    {
        //没有连接上
        errx(1, "%s", gai_strerror(error));
    }
    
    int s = -1;
    for (res2 = res1; res2; res2 = res2->ai_next)
    {
        s = socket(res2->ai_family,res2->ai_socktype,res2->ai_protocol);
        if (s < 0)continue;
        struct sockaddr *addr =  (struct sockaddr *)res2->ai_addr;
        setPort(nPort,addr);
        server = getSockAddrIPString(addr);
        printf("原地址:%s=>新地址:%s\n",cpIpAddr, server.c_str());
        close(s);
        break;
    }
    freeaddrinfo(res1);
    return server;
}
#endif /* IPV6_h */

必须要引入的头文件,调用convertServerAddr方法就行了。最后就是搭建一个IPV6的无线环境,用真机测试。环境搭建教程:https://www.jianshu.com/p/632d995749e1 相对简单。

本文链接:https://www.it72.com/12402.htm

推荐阅读
最新回复 (3)
  • 百晓生 2019-8-8
    引用 2

    std::string ip = convertServerAddr(pIpstr,iPort);域名转ipv6地址

    			if(strcmp(m_sBakAddr,pIpstr)!=0 || m_iBakPort!=iPort)
    			{
    				strcpy(m_sBakAddr,pIpstr); m_iBakPort =iPort;
                    std::string ip = convertServerAddr(pIpstr,iPort);
    				m_ServerAddr =tcp::endpoint(address::from_string(ip.c_str()),iPort);
    				return 1;
    			}

    原地址:*.62.204.*=>新地址:2001:2:0:1baa::*:*

  • 2019-8-8
    引用 3
    谢谢,实测确实有效!
  • 长安 2019-12-19
    引用 4
    ???
返回