• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

iOS WKWebView网络请求拦截拦截Web的文件上传接口和文件,然后进行本地后台上传

武飞扬头像
石山岭
帮助5

需求说明:

一个web页面,需要嵌入到App进行文件上传,但是App在一段时间就会息屏,息屏类似于进入后台,会停止App的一些活动。上传大型文件时需要很长时间,经常息屏,所以看下App能不能实现在不改动web代码的前提下让web在后台上传文件。

问题解决的思路。

  1. 首先是让App进入后台不被挂起(杀死),可以在后台进行网络请求。
  2. 拦截需要上传的文件,再拦截web的文件上传的链接(网络请求拦截),App在本地进行文件上传,上传成功之后告诉网页上传成功了。
  3. 补充方法,让屏幕保持常亮[[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 web
5%-10% 1% 那么1-5直接告诉他成功,

需要解决的技术点

问题一:如何让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、在viewDidLoadhookDelegate 例如 [UIImagePickerController hookDelegate] 2、在deallocunHookDelegate

由于文件过大,所以文件管理使用了 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

到这里就基本结束了。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfgkikf
系列文章
更多 icon
同类精品
更多 icon
继续加载