CM *_*ram 46 html iphone image uiwebview nsurlprotocol
之前已经提出过类似的问题,但我找不到解决方案.
这是我的情况 - 我的UIWebView加载了一个远程html页面.网页中使用的图像在构建时是已知的.为了使页面加载更快,我想将图像文件打包到iOS应用程序中并在运行时替换它们.
[请注意,html是远程的.我总是得到从本地加载html和图像文件的答案 - 我已经这样做了]
我得到的最接近的建议是在html页面和iOS应用程序中使用自定义URL方案,如myapp://images/img.png,使用NSURLProtocol子类截取myapp:// URL并用本地替换图像图片.在理论上听起来不错,但我没有遇到一个完整的代码示例来证明这一点.
我有Java背景.我可以使用自定义内容提供商轻松地为Android做到这一点.我相信iOS/Objective-C必须存在类似的解决方案.我没有足够的Objective-C经验可以在很短的时间内自行解决.
任何帮助将不胜感激.
Nic*_*ver 85
确定这里是一个例子如何继承NSURLProtocol和提供的图像(image1.png),其已经在包.下面是子类的标题,实现以及如何在viewController(不完整的代码)和本地html文件(可以与远程文件轻松交换)中使用它的示例.我调用了自定义协议:myapp://正如你在底部的html文件中看到的那样.
谢谢你的提问!我在很长一段时间里都在问这个问题,花时间计算这个问题的时间非常值得.
编辑: 如果有人在我目前的iOS版本下运行我的代码有困难,请看看sjs的答案.当我回答这个问题时,它正在工作.他指出了一些有用的补充并纠正了一些问题,所以也给他道具.
这是它在我的模拟器中的样子:

MyCustomURLProtocol.h
@interface MyCustomURLProtocol : NSURLProtocol
{
NSURLRequest *request;
}
@property (nonatomic, retain) NSURLRequest *request;
@end
Run Code Online (Sandbox Code Playgroud)
MyCustomURLProtocol.m
#import "MyCustomURLProtocol.h"
@implementation MyCustomURLProtocol
@synthesize request;
+ (BOOL)canInitWithRequest:(NSURLRequest*)theRequest
{
if ([theRequest.URL.scheme caseInsensitiveCompare:@"myapp"] == NSOrderedSame) {
return YES;
}
return NO;
}
+ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)theRequest
{
return theRequest;
}
- (void)startLoading
{
NSLog(@"%@", request.URL);
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[request URL]
MIMEType:@"image/png"
expectedContentLength:-1
textEncodingName:nil];
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"image1" ofType:@"png"];
NSData *data = [NSData dataWithContentsOfFile:imagePath];
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[[self client] URLProtocol:self didLoadData:data];
[[self client] URLProtocolDidFinishLoading:self];
[response release];
}
- (void)stopLoading
{
NSLog(@"something went wrong!");
}
@end
Run Code Online (Sandbox Code Playgroud)
MyCustomProtocolViewController.h
@interface MyCustomProtocolViewController : UIViewController {
UIWebView *webView;
}
@property (nonatomic, retain) UIWebView *webView;
@end
Run Code Online (Sandbox Code Playgroud)
MyCustomProtocolViewController.m
...
@implementation MyCustomProtocolViewController
@synthesize webView;
- (void)awakeFromNib
{
self.webView = [[[UIWebView alloc] initWithFrame:CGRectMake(20, 20, 280, 420)] autorelease];
[self.view addSubview:webView];
}
- (void)viewDidLoad
{
// ----> IMPORTANT!!! :) <----
[NSURLProtocol registerClass:[MyCustomURLProtocol class]];
NSString * localHtmlFilePath = [[NSBundle mainBundle] pathForResource:@"file" ofType:@"html"];
NSString * localHtmlFileURL = [NSString stringWithFormat:@"file://%@", localHtmlFilePath];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:localHtmlFileURL]]];
NSString *html = [NSString stringWithContentsOfFile:localHtmlFilePath encoding:NSUTF8StringEncoding error:nil];
[webView loadHTMLString:html baseURL:nil];
}
Run Code Online (Sandbox Code Playgroud)
file.html
<html>
<body>
<h1>we are loading a custom protocol</h1>
<b>image?</b><br/>
<img src="myapp://image1.png" />
<body>
</html>
Run Code Online (Sandbox Code Playgroud)
Sam*_*uri 39
尼克韦弗有正确的想法,但他的答案中的代码不起作用.它也打破了一些命名约定,从不用NS前缀命名自己的类,并遵循大写首字母缩写词的约定,例如标识符名称中的URL.为了让这个易于理解,我会坚持他的命名.
这些变化很微妙但很重要:丢失未分配的requestivar,而是参考提供的实际请求,NSURLProtocol并且工作正常.
NSURLProtocolCustom.h
@interface NSURLProtocolCustom : NSURLProtocol
@end
Run Code Online (Sandbox Code Playgroud)
NSURLProtocolCustom.m
#import "NSURLProtocolCustom.h"
@implementation NSURLProtocolCustom
+ (BOOL)canInitWithRequest:(NSURLRequest*)theRequest
{
if ([theRequest.URL.scheme caseInsensitiveCompare:@"myapp"] == NSOrderedSame) {
return YES;
}
return NO;
}
+ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)theRequest
{
return theRequest;
}
- (void)startLoading
{
NSLog(@"%@", self.request.URL);
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:self.request.URL
MIMEType:@"image/png"
expectedContentLength:-1
textEncodingName:nil];
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"image1" ofType:@"png"];
NSData *data = [NSData dataWithContentsOfFile:imagePath];
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[[self client] URLProtocol:self didLoadData:data];
[[self client] URLProtocolDidFinishLoading:self];
[response release];
}
- (void)stopLoading
{
NSLog(@"request cancelled. stop loading the response, if possible");
}
@end
Run Code Online (Sandbox Code Playgroud)
Nick的代码的问题是子类NSURLProtocol不需要存储请求.NSURLProtocol已经有请求,您可以使用-[NSURLProtocol request]相同名称的方法或属性访问.由于request他的原始代码中的ivar从未被分配,因此它总是nil(如果它被分配,它应该已经在某处释放).该代码不能也不起作用.
其次,我建议在创建响应之前读取文件数据,并将其[data length]作为预期内容长度而不是-1 传递.
最后,-[NSURLProtocol stopLoading]不一定是错误,它只是意味着你应该停止响应,如果可能的话.用户可能已取消它.
| 归档时间: |
|
| 查看次数: |
37859 次 |
| 最近记录: |