编译kxmovie

KXMovie是基于ffmpeg的iOS播放器代码

下载KXMovie代码

地址:https://github.com/kinglonghuang

 git clone git://github.com/kinglonghuang/kxmovie.git

下载编译FFmpeg

在 https://github.com/FFmpeg/FFmpeg 中下载应该比clone快些,解压拷贝到kxmovie工程目录下的FFmpeg目录中。

下载gas-preprocessor.pl

地址:https://github.com/libav/gas-preprocessor

 sudo cp gas-preprocessor.pl /usr/bin sudo
 sudo chmod 777 /usr/bin/gas-preprocessor.pl

增加x86_64架构

用xcode打开kxmovie工程中的Rakefile文件,按i386的规则对应增加x86_64配置,保存关闭。

下载并编译x264

下载x264代码:http://www.videolan.org/developers/x264.html
下载x264 iOS build script:https://github.com/kewlbear/x264-ios

编译armv7架构库,成功后会在x264/armv7中生成include和lib目录。

./build-x264.sh armv7

如果报“Out of tree builds are impossible with config.h/x264_config.h in source dir.”,则删除x264中的config.h/x264_config.h。

增加x264支持

ffmpeg中只默认支持h264解码,没有支持编码,增强编译出的ffmpeg静态库功能。

以编译armv7为例,打开Rakefile,在FFMPEG_BUILD_ARGS_ARMV7中后面添加

'--enable-libx264',
'--enable-encoder=libx264',
'--enable-gpl',
"--extra-cflags='-I/xxx/workspace/kxmoviex/x264/armv7/include'",
"--extra-ldflags='-L/xxx/workspace/kxmoviex/x264/armv7/lib'"

修改为只执行armv7任务,

task :default => [:check_gas_preprocessor, :build_ffmpeg_armv7]

下载并编译faac

下载faac
http://nchc.dl.sourceforge.net/project/faac/faac-src/faac-1.28/faac-1.28.tar.gz
编译参考下面的链接,注意把编译脚本文件放到faac目录内
http://blog.csdn.net/cjj198561/article/details/38382889
https://github.com/EchoLiao/faac-prebuild/blob/master/build_ios.sh

增加faac支持

ffmpeg中自带的是acc编码

以编译armv7为例,打开Rakefile,在FFMPEG_BUILD_ARGS_ARMV7中后面添加

'--enable-libfaac',
'--enable-encoder=libfaac',
'--enable-nonfree',
"--extra-cflags='-I/xxx/workspace/kxmoviex/faac/build/install/armv7/include'",
"--extra-ldflags='-L/xxx/workspace/kxmoviex/faac/build/install/armv7/lib'"

重新编译ffmpeg

修改sdk版本号

用xcode打开kxmovie工程目录下的Rakefile,修改SDK_VERSION=’9.1’。或进入 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/,查看里面的目录快捷方式名中的版本号,或打开模拟器在关于中查看版本号。

运行

cd kxmovie
rake

执行rake命令

用xcode打开kxmovie工程目录下的Rakefile,修改SDK_VERSION=’9.2’。或进入 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/,查看里面的目录快捷方式名中的版本号,或打开模拟器在关于中查看版本号。

cd kxmovie
rake

如果报“XcodeDefault.xctoolchain/usr/bin/ranlib: archive member, does not match previous archive members cputype ”类似错误,清理对应目录中的.o文件。

在kxmoviex工程中,把x264/armv7中的库,和ffmpeg生成的库都加入到工程中。

附:架构小提示

F104CB3A425C674660FE506EF2B128C2

架构对应的设备:

 armv6 设备: iPhone, iPhone2, iPhone3G, 第一代、第二代 iPod Touch
 armv7 设备: iPhone3GS, iPhone4, iPhone4S;iPad, iPad2, iPad3(The New iPad), iPad mini;iPod Touch 3G, iPod Touch4
 armv7s设备: iPhone5, iPhone5C, iPad4(iPad with Retina Display)
 arm64 设备: iPhone5S, iPad Air, iPad mini2(iPad mini with Retina Display)

参考文章:
http://stackoverflow.com/questions/5056600/how-to-install-gas-preprocessor
http://www.cnblogs.com/sunminmin/p/4463741.html
http://blog.sina.com.cn/s/blog_864456e50101emmx.html

UITabBarController

创建TabBarItem示例

    [[UITabBar appearance] setTintColor:ThemeColor];
    
    UIViewController* viewController = [[PreferentialViewController alloc] initWithNibName:nil bundle:nil];
    UINavigationController* nav1 = [[UINavigationController alloc] initWithRootViewController:viewController];
    UIImage* selectedImage=[UIImage imageNamed:@"main_selected.png"];
    //使selectedImage不受着色影响
    selectedImage=[selectedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    UITabBarItem* tabBarItem = [[UITabBarItem alloc] initWithTitle:@"title" image:[UIImage imageNamed:@"main.png"] selectedImage:selectedImage];
    [tabBarItem setTitlePositionAdjustment:UIOffsetMake(0, -3)];
    nav1.tabBarItem = tabBarItem;

UIScrollView

选中UIButton后滑动UIScrollView无效

重写touchesShouldCancelInContentView方法

-(BOOL)touchesShouldCancelInContentView:(UIView *)view
{
    return YES;
}

循环滚动效果

实现思路:内部封装一个UIScrollView,它的contentSize占3个页面,动态控制这3个页面对应的view。即内部适配了一个scrollView。

特殊地,只有一个页面时,不需要显示页码指示,也不需要循环滚动。有2个页面时,也不需要循环滚动,因为向左或向右拖动时的耗费是相同的。

KeyChain

iOS系统有一个KeyChain,每个程序都可以往KeyChain中记录数据,而且只能读取到自己程序记录在KeyChain中的数据。iOS中Security.framework框架提供了四个主要的方法来操作KeyChain

 // 查询
 OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef *result);
 // 添加
 OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result);
 // 更新
 OSStatus SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate);
 // 删除
 OSStatus SecItemDelete(CFDictionaryRef query)

苹果还允许同一个开发商的各APP之间互访数据,即在调SecItemAdd添加数据的时候指定AccessGroup访问组,一个APP可以同时属于多个组。

IAP 应用内支付

在手机上测试购买填写邮箱地址和密码

提交ipa,images.xcaccessts中缺少图Icon配置

iTunes Store Operation Failed
description length:437418

iTunes Store Operation Failed
ERROR ITMS-90022: "Missing required icon file. The bundle does not contain an app icon for iPhone / iPod Touch of exactly '57x57' pixels, in .png format for iOS versions < 7.0."

iTunes Store Operation Failed
WARNING ITMS-90704: "Missing App Store Icon. iOS Apps must include a 1024x1024px App Store Icon in PNG format. Without providing the icon in the Asset Catalog or via iTunes Connect, apps cannot be submitted for App Review or Beta App Review. Refer to https://developer.apple.com/ios/human-interface-guidelines/icons-and-images/app-icon/ for more information."

UIView

设置亮度

通过修改alpha可以调节亮度,但会出现透明问题。还可以通过添加一个子view来调节亮度。

-(void)setAdView:(UIView*)adView opacity:(float)opacity
{
    if(opacity<1.0)
    {
        UIView* v=[adView viewWithTag:KMaskViewTag];
        if(!v)
        {
            v=[[[UIView alloc] initWithFrame:adView.bounds] autorelease];
            v.backgroundColor=[[UIColor blackColor] colorWithAlphaComponent:opacity];
            v.tag=KMaskViewTag;
            v.userInteractionEnabled=NO;
            [adView addSubview:v];
            
            v.alpha=0.0;
            [UIView animateWithDuration:0.30 animations:^{
                v.alpha=1.0;
            }];
        }
    }
    else
    {
        UIView* v=[adView viewWithTag:KMaskViewTag];

        [UIView animateWithDuration:0.30 animations:^{
            v.alpha=0.0;
        } completion:^(BOOL finished) {
            [v removeFromSuperview];
        }];
    }
}

viewWithTag

viewWithTag方法会在所有子view中递归查询,返回找到的第一个视图。

侧移效果实现过程

对框架view照相,把要显示的新view添加到框架view中,把照相view添加到框架view中,对照相view执行侧移动画,即动画中改变它的frame。相反的过程恢复到原状态。

    UIView* mainView = self.navigationController.view;
    UIImage* captureImage = [mainView captureView];

    [mainView addSubview:newView];
    UIImageView* theCaptureView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, mainView.frame.size.width, mainView.frame.size.height)];
    theCaptureView.backgroundColor = [UIColor whiteColor];
    [theCaptureView setImage:captureImage];
    [mainView addSubview:theCaptureView];
    [UIView animateWithDuration:0.25f animations:^{
        [theCaptureView setFrame:CGRectMake(-245, 44, mainView.frame.size.width, mainView.frame.size.height-44*2)]; //320-245=75
    } completion:^(BOOL finished) {
        theCaptureView.userInteractionEnabled = YES;
        UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(recoveryView:)];
        [theCaptureView addGestureRecognizer:tap];
    }];
- (void)recoveryView:(id)sender
{
    UIView* mainView = [self.navigationController view]; n]
    if (theCaptureView) {
        [UIView animateWithDuration:0.25f animations:^{
            [theCaptureView setFrame:CGRectMake(0, 0, mainView.frame.size.width, mainView.frame.size.height)];
        } completion:^(BOOL finished) {
            [theCaptureView removeFromSuperview];
            [theNewView removeFromSuperview];
        }];
    }
}

- (UIImage*)captureView
{
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0.0);
    [self.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage* screenImg = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return screenImg;
}

contentMode

按钮中的图片等比适应按钮的尺寸

imageView.clipsToBounds=YES;
button.imageView.contentMode=UIViewContentModeScaleAspectFill;
button.imageView.contentMode=UIViewContentModeScaleAspectFit;

图片全圆角

imageView_.layer.cornerRadius = 15;//width/2
imageView_.layer.masksToBounds = YES;

如果需要全圆角边框可以在父view相同位置插入一个稍大一点的全圆角背景图,或尝试设置border。

 

UIImage

imageName会把image缓存到手机内存里,不适合大量图片浏览会越来越卡。

imageWithContentFile是只显示图片而不加载到手机内存里。所以在出来大量图片浏览的时候要用imagewithcontentfile。

尺寸

父view尺寸小,默认情况下内部的大按钮仍会显示全。

objc动态特性

关联对象

相当于android中的setObject

要引入 <objc/runtime.h>

设置关联:

objc_setAssociatedObject(array, &overviewKey, overview, OBJC_ASSOCIATION_RETAIN);

获取关联的对象:

NSString * associatedObject = (NSString *)objc_getAssociatedObject(array, &oveviewKey);

断开关联也是使用objc_setAssociatedObject函数,设置被关联的对象为nil,此时关联策略可任意:

objc_setAssociatedObject(array, &overviewKey, nil, OBJC_ASSOCIATION_ASSIGN);

生成推送证书

1.生成cer证书文件
点击App IDs,点击应用对应的AppID,如果看到Push Notifications后为Configurable,说明还未正常启用推送功能;
点击Edit,在下方下载证书;或Create Certificate…,需要上传CSR文件。

2、把SSL证书.cer文件转换为.pem文件:

openssl x509 -in reading_development.cer -inform der -out reading_development.pem
openssl x509 -in reading_production.cer -inform der -out reading_production.pem

3、把私钥.p12文件转换为.pem文件:

openssl pkcs12 -nocerts -in wwk_develope.p12 -out reading_development_key.pem
openssl pkcs12 -nocerts -in wwk_distribute.p12 -out reading_production_key.pem

这里需要输入导出.p12文件时的设置的密码。然后,需要对生成的pem文件设置一个密语,这个密语在连接服务器时使用。

4、把前面生成的这两个pem文件(证书和私钥)合并成一个pem文件:

cat reading_development.pem reading_development_key.pem > reading_development_result.pem
cat reading_production.pem reading_production_key.pem > reading_production_result.pem

这3步就完成了推送证书的生成,下面的步骤是测试证书及连接是否可用。

5.测试能否连接到APNS

telnet gateway.sandbox.push.apple.com 2195

发送一个规则的,不加密的连接到APNS服务。要确保防火墙允许2195端口。

6.使用2、3步生成的SSL证书和私钥pem文件测试链接苹果服务器:

openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert reading_development.pem -key reading_development_key.pem

需要输入第2步设置的密语

然后有大段输出。如果链接成功,随便输入一个字符后按下回车,服务器就会断开链接。如果连接异常OpenSSL会返回错误信息。

如果在最后看到下面的内容说明成功了:
CONNECTED(00000003)

Verify return code: 0 (ok)

或者看到像这样的提示:verify error:num=20:unable to get local issuercertificate verify return:0 其实也是没问题的。

URL Schema

配置URL Schema的作用

在本应用程序的.plist文件中配置URL Schema,目的是供其它应用以通过这个schema启动本应用程序。

实现分享功能配置一堆URL Schema

在应用中实现分享内容到微博,微信,qq等一堆开放平台中功能,需要根据各开放平台的规则要求,配置一堆schema,其schema规则一般是固定标识+在其平台上注册到的应用id,分享完成后,这些社交软件会询问是留在这里还是回到原应用,通过这个schema回调就会回到我们的应用程序。

compiling IB documents for earlier than ios 7 is no longer supported

http://blog.csdn.net/u011415099/article/details/78136282

Images.xcassets

LaunchImage中图片像素尺寸:
iPhone X ios 11+ 1125×2436
Retina HD 5.5 iOS 8+ 1242×2208
Retina HD 4.7 iOS 8+ 750×1334
2x iOS 7+ 640×960
Retina 4 iOS 7+ 640×1136

xcode Images.xcassets 特性使用
https://www.jianshu.com/p/1034748e3fef

Block

Block简介

  • Block 是 iOS 4.0 和 Mac OSX 10.6 引入的一个新特性。
  • 没有 Block 时, 一般会用代理或者 NSNotificationCenter回调一个方法,在一个地方开启了一个任务, 然后在另外一个地方处理它的结果。Block能将和一个任务相关的所有代码都放在一个地方。
  • 在其它语言中 Block 又叫做闭包, 因为他们包含了定义时的状态。 Block 会为所有和它在同一作用范围内的局部变量创建一个常量拷贝。
  • Block 是一个标准 Objective-C 对象, 可以作为参数传递, 作为方法或函数的返回值, 赋值给变量。

Block 的声明格式

return_type (^block_name)(param_type, param_type, ...)

^符号表示定义的是一个 Block。
代码示例:

 int (^add)(int,int)

Block 的定义格式:

 ^return_type(param_type param_name, ...) { ... return return_type; }

定义 Block 时, 返回值类型可选,可以继承它里面代码的返回值类型
示例:

 ^(int number1, int number2){ return number1+number2; }

声明并定义Block

示例:

 int (^add)(int,int) = ^(int number1, int number2)
 {
 return number1+number2;
 };

循环引用(retain-cycle)问题

如果这个block没有使用当前实例的任何成员,那么当前实例不会被增加引用计数。
如果objc类实例方法中的block如果被复制至heap,那么当前实例会被增加引用计数,当这个block被释放时,此实例会被减少引用计数。但若block和当前实例互相直接或间接retain,则会出现循环引用问题。

解决方法:不直接使用self而先将self赋值给一个__block临时变量,然后再使用这个临时变量。示例:

__block DetailViewController* tempSelf = self;
//或者 __block typeof(self) tempSelf = self;
 [replyViewController_ setFinishBlock:^{
 [tempSelf method];
 tempSelf->member=0;
 }];

__block关键字的作用是让block取消对tempSelf的强参照,以避免循环参照。在ARC下,要使用__weak不是 __block来避免block循环引用;

若出现typeof(self) Expected ‘;’ at end of declaration编译错误,需要修改设置 Apple LLVM 5.1 Language C Language Dialect 值为 GNU99 [-std=gnu99]

You do not have to jump through this hoop for every block you make because most blocks have a very short lifespan. Just be aware that if you have a block that has the same lifetime as its owning object and you are freeing the block at -dealloc time, you can get a retain cycle.

http://www.informit.com/articles/article.aspx?p=1749597&seqNum=10

外部变量问题

若非即执行的block中外部变量是可变的,则注意在每次调用时要重新生成一个block。

 BOOL isFriends=[INSTANCE.contextData isFriendWithUser:userInfo];
 if(!replyViewController_)
 {
 replyViewController_=[[ReplyChatViewController alloc] initWithPlaceholder:@"打个招呼吧"];
 }
 //每次要重新设置block,因为其使用的外部变量值每次不同。
 __block MapViewController* tempself=self;
 [replyViewController_ setFinishBlock:^{
 if(!isFriends && INSTANCE.serverSetting.costMakeFriends>0)
 {
 [tempself performSelector:@selector(submitPayOffer) withObject:nil afterDelay:0.5];
 }
 }];
 [replyViewController_ showAnimated:self.view.window];