需求场景:H5 页面 读取系统相册 ,把选中的图片上传给前端 H5. (H5不能直接读取沙盒的路径)
方案1:读取到的二进制baseEncode 字符串形式交互
弊端:
- 安全性问题:JavaScript在浏览器中运行,可能存在潜在的安全风险,需要谨慎处理用户照片,以免导致隐私泄露或安全问题。
- 性能问题:读取大型图片文件并转换为数据URL可能影响页面加载和响应速度,特别是处理大型图片文件时会消耗较多的内存和时间。
- 浏览器兼容性:不同浏览器对文件API的支持程度有所不同,可能导致在某些浏览器上无法正常读取或处理图片文件。
- 移动设备限制:在移动设备上,尤其是iOS设备上,由于安全性限制和隐私保护,可能无法直接访问系统相册,限制了文件系统的访问。
最主要就是这个性能问题,如果是多张图片,图片大小不可控,更会引起问题。
方案2:GCDWebServer 在 iOS 应用中创建本地服务器处理图片上传
优点:
- 本地处理:能够在 iOS 应用内部启动本地服务器,允许直接从 H5 页面上传图片到应用本地,便于应用内部的处理和管理。
- 灵活性:可以在服务器端对上传的图片数据进行必要的处理,如压缩、裁剪、格式转换等操作,以满足应用特定的需求。
- 实时性:可通过本地服务器实现即时通信,快速响应上传请求,加快图片处理速度。
- 可定制性:GCDWebServer 提供了灵活的 API,允许开发者自定义路由和处理逻辑,以适应不同的业务场景。
潜在的缺点:
- 复杂性:对于不熟悉服务器端开发的开发者来说,使用 GCDWebServer 可能需要一定的学习成本,特别是对于涉及到网络编程和服务器配置方面的知识。
- 维护成本:维护一个本地服务器需要考虑到安全补丁、更新、故障排查和性能优化等方面,这可能需要较多的时间和精力。
- 性能问题:在处理大量或大型文件时,可能会对设备的性能产生一定的影响,尤其是在资源有限的设备上,可能导致性能下降或资源耗尽。
- 安全风险:开放一个本地服务器可能存在一些潜在的安全风险,例如未经验证的访问、恶意请求和攻击等问题,需要做好安全防护措施。
- 依赖性:应用依赖于第三方库 GCDWebServer,如果该库的更新不及时或存在 bug,可能会影响应用的稳定性和功能。
- 网络限制:本地服务器通常只能在局域网内使用,如果需要通过公网访问,需要考虑网络环境和配置公网访问的安全性。
- 并发处理:GCDWebServer 默认采用 GCD(Grand Central Dispatch)进行请求的处理,如果处理大量并发请求,可能会对服务器性能产生影响,需要进行优化。
鉴于,我们在局部功能使用,按需开启服务,按需关闭服务,最终决定使用GCDWebServer。
使用举例子
html 测试文件内容:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>展示图片</title>
</head>
<body>
<script>
function showImage(base64) {//data base64 形式
var img = new Image();
img.src = "data:image/png;base64," + base64;
img.style.width = "300px";
img.style.height = "200px";
document.body.appendChild(img);
}
function showImages1(imageStr) {//路由地址形式
var images = imageStr.split(",");
for (var i = 0; i < images.length; i++) {
var img = new Image();
img.src = "http://localhost:9999/Documents/KFZAlbumCameraRoot/" + images[i];
img.style.width = "300px";
img.style.height = "200px";
document.body.appendChild(img);
}
}
</script>
</body>
</html>pod 'GCDWebServer' #搭建本地服务器
创建管理类:
KFZGCDWebServer.h KFZGCDWebServer.m#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
///本地服务器管理
@interface KFZGCDWebServer : NSObject
- (void)startWebServer;
- (void)stopWebServer;
@end
NS_ASSUME_NONNULL_END
#import "KFZGCDWebServer.h"
#import "GCDWebServer.h"
@interface KFZGCDWebServer () <GCDWebServerDelegate>
@property (nonatomic, strong) GCDWebServer *localServer;
@end
@implementation KFZGCDWebServer
- (instancetype)init
{
self = [super init];
if (self) {
}
return self;
}
#pragma mark - event
- (void)startWebServer
{
if (!self.localServer) {
GCDWebServer *webServer = [[GCDWebServer alloc] init];
//这里最关键的是需要最后运行起来逐步调试 这个路由的路径是否是你期望的路径,容易多个/, 或者可能路径重复了所以这里要特别注意
[webServer addGETHandlerForBasePath:@"/" directoryPath:NSHomeDirectory() indexFilename:nil cacheAge:3600 allowRangeRequests:YES];
self.localServer = webServer;
}
NSMutableDictionary* options = [NSMutableDictionary dictionary];
[options setObject:[NSNumber numberWithInteger:9999] forKey:GCDWebServerOption_Port];
// [options setValue:@"GCD Web Server" forKey:GCDWebServerOption_BonjourName];//⚠️注意这里要用固定的端口号和bonjourName为nil,以成功绕过苹果的本地网络权限检测
[options setValue:@(false) forKey:GCDWebServerOption_AutomaticallySuspendInBackground]; //⚠️不主动挂起处理
//
[self.localServer startWithOptions:options error:NULL];
}
- (void)stopWebServer
{
[_localServer stop];
_localServer = nil;
}测试代码:KFZTestHtmlVC.h KFZTestHtmlVC.m
@interface KFZTestHtmlVC () <KFZAlbumCameraDelegate>
@property (nonatomic, strong) WKWebView *webView;
@property (nonatomic, strong) KFZGCDWebServer *localWebServer;
@end
@implementation KFZTestHtmlVC
- (void)viewDidLoad {
[super viewDidLoad];
[self initWebServer];
[self addNavView];
[self configSubviews];
}
- (void)dealloc
{
[_localWebServer stopWebServer];
//
[KFZImageCacheManager clearCurrentImagePath:self.localIdentifier];
}
#pragma mark - event
- (void)rightButtonClick
{
[KFZAlbumCameraVC showPageFromVC:self
maxPictureNum:120
defaultType:KFZAlbumCameraIndex_Camera
isOnlyType:false
isBlue:true
callNextStepResult:^(NSArray * _Nonnull resultImages) {
}];
}
#pragma mark - KFZAlbumCameraDelegate
/** 点击下一步 图片出口回执 */
- (void)handleCallNextStepResultImages:(NSArray * _Nullable )resultImages
{
DLog(@"%@",resultImages);
//这里回执的是图片相对路径 eg "business1703064143/album1703064157/1703064185899.jpg" 然后在前端的 "http://localhost:9999/Documents/KFZAlbumCameraRoot/"拼成一个完整图片地址就可以展示出来了// 使用 JavaScript 将参数传递给 H5
NSString *script =[NSString stringWithFormat:@"showImages1('%@')",[resultImages componentsJoinedByString:@","]];[self.webView evaluateJavaScript:script completionHandler:nil];
// server
//
[self.navigationController popViewControllerAnimated:true];
}
- (void)initWebServer {
self.localWebServer = [[KFZGCDWebServer alloc]init];
[self.localWebServer startWebServer];
}
#pragma mark - private
- (void)configSubviews
{
// webView
[self.view addSubview:self.webView];
[self.webView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.bottom.right.equalTo(self.view);
.equalTo(self.stateNavBgView.mas_bottom);
}];
[self loadWebRequest];
//documentPath
NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES) objectAtIndex:0];
DLog(@"documentPath = %@",documentPath);
}
- (void)loadWebRequest
{
NSURL *url = [[NSBundle mainBundle] URLForResource:@"index" withExtension:@"html"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}
- (void)addNavView
{
UIButton *rightButton = [[UIButton alloc] init];
UIColor *color = [UIColor kfz_colorTitle];
[rightButton setTitle:@"相机" forState:UIControlStateNormal];
[rightButton setTitleColor:color forState:UIControlStateNormal];
[rightButton.titleLabel setFont:[UIFont kfz_fontRegularSize:14]];
[rightButton addTarget:self action:@selector(rightButtonClick) forControlEvents:UIControlEventTouchUpInside];
//右边导航按钮
[self.custemNavigation addSubview:rightButton];
[rightButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(0);
make.centerY.equalTo(self.custemNavigation.mas_centerY);
make.width.equalTo(@(80));
.bottom.equalTo(@(0));
}];
}
#pragma mark - getter setter
- (WKWebView *)webView
{
if (!_webView) {
_webView = [[WKWebView alloc]init];
}
return _webView;
}
@end图片沙盒相对路径 和 GCDWebServer 服务开启的基地址进行拼接出来的
效果图 :

















