需求说明:
一个web页面,需要嵌入到App进行文件上传,可是App在一段时刻就会息屏,息屏类似于进入后台,会中止App的一些活动。上传大型文件时需要很长时刻,常常息屏,所以看下App能不能实现在不改动web代码的前提下让web在后台上传文件。
问题处理的思路。
- 首要是让App进入后台不被挂起(杀死),可以在后台进行网络恳求。
- 阻拦需要上传的文件,再阻拦web的文件上传的链接(网络恳求阻拦),App在本地进行文件上传,上传成功之后告知网页上传成功了。
- 补充办法,让屏幕坚持常亮
[[UIApplication sharedApplication] setIdleTimerDisabled: YES]
不过要记得在dealloc
中设置为 NO.
在iOS16下,即使App一向在后台存活,WKWebView会中止网络恳求,所以有必要进行阻拦,然后App进行文件上传操作,然后及时回来给网页,这样就可以确保WKWebView的网络恳求存活.
在iOS17beta3中,不进行阻拦的情况下,只要确保App在后台存活,WKWebView可以进行网络恳求。后续再iOS17正式版发布之后在进行测试是否真的支持。
阻拦后文件上传有两种计划,
计划一:
由于阻拦到的文件formData丢掉,可是可以阻拦到上传的 range,也便是文件范围,App对文件进行分段,然后自己组装formData数据进行实时上传。
截取部分文件代码
NSFileHandle * readFileHandle;
//offset偏移量 size长度
[readFileHandle seekToFileOffset:offset];
NSData * fileFragmentData = [fileModel.readFileHandle readDataOfLength:size];
计划二:
App经过AFNetworking进行文件上传,并通知记载上传进展,在阻拦到网页的接口时获取网页当前进展,假如App进展超越网页进展,那么直接回来网页,告知他当前已经上传成功,形成一个“伪同步”。
例如一个文件10M,经过表单分成10段上传, App假如网速很快,1秒上传了8M, 那么在阻拦的网页中,前八次恳求都回来成功。 第九次上传,进入地道,App信号不好了。上传了20秒,那么阻拦到web第九次恳求就一向等候,直到App恳求成功,在进行web接口的呼应。
需要处理的技术点
问题一:如何让App在一向在后台存活。
处理:经过让App在后台播映无声响乐的办法可以做到让App理论上的无限存活。
问题二:怎样阻拦要上传的文件。
处理:运用Runtime办法交流,Hook到上传的文件。
问题三:怎样阻拦文件上传链接(网络恳求)。
处理:运用WKURLSchemeHandler
下面详细介绍这些问题的处理过程。
一、如何让App在一向在后台存活。
iOS7今后提供的后台接口形式
1、Background Audio,这是后台的音频,类似于各种音乐播映器。
2、Location Services,这是后台的定位,类似于各种地图导航应用。
3、VoIP,后台语音服务,类似于各种聊天软件。
4、Newsstand,报刊杂志后台自动下载更新,其可以自动实时更新。
我选择的是第一种,可以做到无感知。简而言之便是在后台循环播映一段无声地音乐。
代码:
/// 创建音乐播映器
- (**void**)creatAVAudioSessionObject{
//设置后台形式和锁屏形式下依然可以播映
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:**nil**];
[[AVAudioSession sharedInstance] setActive: **YES** error: **nil**];
//初始化音频播映器
NSError *playerError;
NSURL *urlSound = [[NSURL alloc]initWithString:[[NSBundle mainBundle]pathForResource:@"laojie" ofType:@"mp3"]];
_audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:urlSound error:&playerError];
_audioPlayer.numberOfLoops = -1;//无限播映
_audioPlayer.volume = 0;
}
/// 开始播映声响
- (**void**)startPlayAudioSession{
**BOOL** isPlay = [_audioPlayer play];
NSLog(@"isPlay===%id", isPlay);
}
/// 中止播映声响
- (**void**)stopPlayAudioSession{
[_audioPlayer stop];
}
运用办法。
首要,打开后台播映音乐开关。

1.在didFinishLaunchingWithOptions
中 调用 creatAVAudioSessionObject
2.在 applicationDidEnterBackground
中 调用 startPlayAudioSession
3.在 applicationWillEnterForeground
中 调用 stopPlayAudioSession
进入后台时,可以写一个倒计时,经过下面代码后台剩余活泼时刻。
[UIApplication sharedApplication].backgroundTimeRemaining
怎样阻拦(Hook)要上传的文件
增加分类办法,在内部经过Runtime更换掉体系的获取文件的办法。然后阻拦从文件体系/相机相册获取的文件。
详细代码看文件:
阻拦UIImagePickerController
阻拦UIDocumentPickerViewController
阻拦PHPickerViewController(iOS14之后从文件办理里面获取文件运用这个)。
运用办法:
1、在viewDidLoad
中 hookDelegate
例如 [UIImagePickerController hookDelegate]
2、在dealloc
中 unHookDelegate
由于文件过大,所以文件办理运用了 NSFileHandle
。
怎样阻拦文件上传链接(网络恳求)
iOS11之后体系提供了:WKURLSchemeHandler
来阻拦WKWenView中的网络恳求。
首要创建一个对象遵守WKURLSchemeHandler
署理,用于进行恳求的阻拦处理。
.h代码检查
.m代码检查
运用办法
WKWebViewConfiguration * con = [[WKWebViewConfiguration alloc] init];
con.allowsInlineMediaPlayback = YES;
con.allowsPictureInPictureMediaPlayback = YES;
GSKHFURLSchemeHandler *Scheme = [GSKHFURLSchemeHandler new];
[con setURLSchemeHandler:Scheme forURLScheme:@"https"];
_webview = [[WKWebView alloc] initWithFrame:CGRectZero configuration:con];
这儿阻拦 https
会 crash,由于体系不支持,所以还需要做一下处理。
给WkWebView增加一个分类,在分类里面经过Runtime,把handlesURLScheme
替换成自己的办法,对阻拦的https
进行独自的处理。
代码如下:
#import "WKWebView+SchemeHandle.h"
#import <objc/runtime.h>
@implementation WKWebView (SchemeHandle)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method originalMethod1 = class_getClassMethod(self, @selector(handlesURLScheme:));
Method swizzledMethod1 = class_getClassMethod(self, @selector(yyhandlesURLScheme:));
method_exchangeImplementations(originalMethod1, swizzledMethod1);
});
}
+ (BOOL)yyhandlesURLScheme:(NSString *)urlScheme {
if ([urlScheme isEqualToString:@"http"] || [urlScheme isEqualToString:@"https"] || [urlScheme isEqualToString:@"file"]) {
return NO; //这儿让回来NO,应该是默许不走体系断语或许其他判断啥的
} else {
return [self handlesURLScheme:urlScheme];
}
}
@end
到这儿就根本结束了。