我想在我的iPhone应用程序中附带一个配置文件,并在需要时安装它。
请注意,我们讨论的是配置配置文件,而不是配置配置文件。
首先,这样的任务是可能的。如果您将一个配置配置文件放在Web页面上并从Safari中单击它,它将被安装。如果您通过电子邮件发送配置文件并单击附件,它也会安装。在这种情况下,“已安装”的意思是“安装UI被调用”--但我甚至无法做到这一点。
因此,我的工作原理是,启动配置文件安装需要将其作为URL导航。我将这个配置文件添加到了我的应用程序包中。
A)首先,我尝试了sharedApp openURL,将文件:// URL放入我的包中。没有这样的运气--什么都没发生。
B)然后我在捆绑包中添加了一个包含配置文件链接的页面,并将其加载到UIWebView中。单击该链接不会执行任何操作。然而,在Safari中从Web服务器加载相同的页面工作得很好--可以单击链接,安装配置文件。我提供了一个UIWebViewDelegate,对每个导航请求都回答是-没有区别。
C)然后我尝试从我在Safari中的包中加载相同的网页(使用sharedApp openURL -什么都没有发生。我猜,Safari在我的应用程序包中看不到文件。
D)在Web服务器上上传页面和配置文件是可行的,但在组织层面上是一种痛苦,更不用说额外的失败来源(如果没有3G覆盖呢?等等)。
所以我最大的问题是:**如何以编程方式安装配置文件?
小问题是:什么可以使UIWebView中的链接不可点击?是否可以从Safari中的捆绑包中加载file:// URL?如果没有,iPhone上是否有一个本地位置可以放置文件,并且Safari可以找到它们?
在B上编辑):问题出在我们链接到一个配置文件的事实上。我把它从.mobileconfig重命名为.xml (因为它真的是XML),修改了链接。链接在我的UIWebView中起作用了。重命名了-同样的东西。看起来UIWebView似乎不愿意做应用程序范围的事情--因为安装配置文件会关闭应用程序。我试着告诉它没问题--通过UIWebViewDelegate --但这不能令人信服。对mailto也是一样的行为: UIWebView中的URL。
mailto: URL的常见的技术是将它们转换为openURL调用,但这对我的情况不太有效,请参阅场景A。
然而,对于itms: URL,UIWebView的工作方式与预期一致...
EDIT2:尝试通过openURL向Safari提供数据URL -不起作用,请查看此处:iPhone Open DATA: Url In Safari
EDIT3:找到了很多关于Safari如何不支持://URL的信息。然而,UIWebView在很大程度上做到了。而且,模拟器上的Safari可以很好地打开它们。后一点是最令人沮丧的。
EDIT4:我一直没有找到解决方案。相反,我构建了一个2位的Web界面,用户可以在其中订购通过电子邮件发送给他们的配置文件。
发布于 2012-03-25 03:44:33
1)安装本地服务器,如RoutingHTTPServer
2)配置自定义头部:
[httpServer setDefaultHeader:@"Content-Type" value:@"application/x-apple-aspen-config"];
3)配置mobileconfig文件(文档)的本地根路径:
[httpServer setDocumentRoot:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]];
4)为了让web服务器有时间发送文件,请添加以下内容:
Appdelegate.h
UIBackgroundTaskIdentifier bgTask;
Appdelegate.m
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSAssert(self->bgTask == UIBackgroundTaskInvalid, nil);
bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
dispatch_async(dispatch_get_main_queue(), ^{
[application endBackgroundTask:self->bgTask];
self->bgTask = UIBackgroundTaskInvalid;
});
}];
}
5)在您的控制器中,使用存储在文档中的mobileconfig的名称调用safari:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString: @"http://localhost:12345/MyProfile.mobileconfig"]];
发布于 2014-01-09 15:39:18
来自malinois的答案对我来说很有效,但是,我想要一个在用户安装mobileconfig后自动返回到应用程序的解决方案。
我花了4个小时,但这里有一个解决方案,构建在malinois的本地http服务器的想法上:你将HTML返回给safari,它会自动刷新;第一次服务器返回mobileconfig,第二次返回自定义的url-scheme来返回你的应用程序。用户体验就是我想要的:应用程序调用safari,safari打开mobileconfig,当用户在mobileconfig上点击“完成”时,safari再次加载你的应用(自定义url方案)。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
_httpServer = [[RoutingHTTPServer alloc] init];
[_httpServer setPort:8000]; // TODO: make sure this port isn't already in use
_firstTime = TRUE;
[_httpServer handleMethod:@"GET" withPath:@"/start" target:self selector:@selector(handleMobileconfigRootRequest:withResponse:)];
[_httpServer handleMethod:@"GET" withPath:@"/load" target:self selector:@selector(handleMobileconfigLoadRequest:withResponse:)];
NSMutableString* path = [NSMutableString stringWithString:[[NSBundle mainBundle] bundlePath]];
[path appendString:@"/your.mobileconfig"];
_mobileconfigData = [NSData dataWithContentsOfFile:path];
[_httpServer start:NULL];
return YES;
}
- (void)handleMobileconfigRootRequest:(RouteRequest *)request withResponse:(RouteResponse *)response {
NSLog(@"handleMobileconfigRootRequest");
[response respondWithString:@"<HTML><HEAD><title>Profile Install</title>\
</HEAD><script> \
function load() { window.location.href='http://localhost:8000/load/'; } \
var int=self.setInterval(function(){load()},400); \
</script><BODY></BODY></HTML>"];
}
- (void)handleMobileconfigLoadRequest:(RouteRequest *)request withResponse:(RouteResponse *)response {
if( _firstTime ) {
NSLog(@"handleMobileconfigLoadRequest, first time");
_firstTime = FALSE;
[response setHeader:@"Content-Type" value:@"application/x-apple-aspen-config"];
[response respondWithData:_mobileconfigData];
} else {
NSLog(@"handleMobileconfigLoadRequest, NOT first time");
[response setStatusCode:302]; // or 301
[response setHeader:@"Location" value:@"yourapp://custom/scheme"];
}
}
..。下面是从应用程序调用的代码(即视图控制器):
[[UIApplication sharedApplication] openURL:[NSURL URLWithString: @"http://localhost:8000/start/"]];
希望这对某些人有帮助。
发布于 2015-10-17 16:07:04
我已经编写了一个类,用于通过Safari安装mobileconfig文件,然后返回到应用程序。它依赖于http服务器引擎Swifter,我发现它工作得很好。我想在下面分享我的代码来做到这一点。它的灵感来自于我在www上发现的多个代码源。所以如果你找到你自己的代码片段,贡献给你。
class ConfigServer: NSObject {
//TODO: Don't foget to add your custom app url scheme to info.plist if you have one!
private enum ConfigState: Int
{
case Stopped, Ready, InstalledConfig, BackToApp
}
internal let listeningPort: in_port_t! = 8080
internal var configName: String! = "Profile install"
private var localServer: HttpServer!
private var returnURL: String!
private var configData: NSData!
private var serverState: ConfigState = .Stopped
private var startTime: NSDate!
private var registeredForNotifications = false
private var backgroundTask = UIBackgroundTaskInvalid
deinit
{
unregisterFromNotifications()
}
init(configData: NSData, returnURL: String)
{
super.init()
self.returnURL = returnURL
self.configData = configData
localServer = HttpServer()
self.setupHandlers()
}
//MARK:- Control functions
internal func start() -> Bool
{
let page = self.baseURL("start/")
let url: NSURL = NSURL(string: page)!
if UIApplication.sharedApplication().canOpenURL(url) {
var error: NSError?
localServer.start(listeningPort, error: &error)
if error == nil {
startTime = NSDate()
serverState = .Ready
registerForNotifications()
UIApplication.sharedApplication().openURL(url)
return true
} else {
self.stop()
}
}
return false
}
internal func stop()
{
if serverState != .Stopped {
serverState = .Stopped
unregisterFromNotifications()
}
}
//MARK:- Private functions
private func setupHandlers()
{
localServer["/start"] = { request in
if self.serverState == .Ready {
let page = self.basePage("install/")
return .OK(.HTML(page))
} else {
return .NotFound
}
}
localServer["/install"] = { request in
switch self.serverState {
case .Stopped:
return .NotFound
case .Ready:
self.serverState = .InstalledConfig
return HttpResponse.RAW(200, "OK", ["Content-Type": "application/x-apple-aspen-config"], self.configData!)
case .InstalledConfig:
return .MovedPermanently(self.returnURL)
case .BackToApp:
let page = self.basePage(nil)
return .OK(.HTML(page))
}
}
}
private func baseURL(pathComponent: String?) -> String
{
var page = "http://localhost:\(listeningPort)"
if let component = pathComponent {
page += "/\(component)"
}
return page
}
private func basePage(pathComponent: String?) -> String
{
var page = "<!doctype html><html>" + "<head><meta charset='utf-8'><title>\(self.configName)</title></head>"
if let component = pathComponent {
let script = "function load() { window.location.href='\(self.baseURL(component))'; }window.setInterval(load, 600);"
page += "<script>\(script)</script>"
}
page += "<body></body></html>"
return page
}
private func returnedToApp() {
if serverState != .Stopped {
serverState = .BackToApp
localServer.stop()
}
// Do whatever else you need to to
}
private func registerForNotifications() {
if !registeredForNotifications {
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.addObserver(self, selector: "didEnterBackground:", name: UIApplicationDidEnterBackgroundNotification, object: nil)
notificationCenter.addObserver(self, selector: "willEnterForeground:", name: UIApplicationWillEnterForegroundNotification, object: nil)
registeredForNotifications = true
}
}
private func unregisterFromNotifications() {
if registeredForNotifications {
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.removeObserver(self, name: UIApplicationDidEnterBackgroundNotification, object: nil)
notificationCenter.removeObserver(self, name: UIApplicationWillEnterForegroundNotification, object: nil)
registeredForNotifications = false
}
}
internal func didEnterBackground(notification: NSNotification) {
if serverState != .Stopped {
startBackgroundTask()
}
}
internal func willEnterForeground(notification: NSNotification) {
if backgroundTask != UIBackgroundTaskInvalid {
stopBackgroundTask()
returnedToApp()
}
}
private func startBackgroundTask() {
let application = UIApplication.sharedApplication()
backgroundTask = application.beginBackgroundTaskWithExpirationHandler() {
dispatch_async(dispatch_get_main_queue()) {
self.stopBackgroundTask()
}
}
}
private func stopBackgroundTask() {
if backgroundTask != UIBackgroundTaskInvalid {
UIApplication.sharedApplication().endBackgroundTask(self.backgroundTask)
backgroundTask = UIBackgroundTaskInvalid
}
}
}
https://stackoverflow.com/questions/2338035
复制相似问题