我测试过:
UIControl().sendAction(#selector(URLSessionTask.suspend), to: UIApplication.shared, for: nil)
用于将应用置于后台,并且可以正常工作。
如何将应用放回前台?
我尝试过:
UIControl().sendAction(#selector(URLSessionTask.resume), to: UIApplication.shared, for: nil)
但是最终它崩溃了...
谢谢
答案 0 :(得分:7)
更新:
由于您已经表明您正在寻找任何技术解决方案,即使那些与App Store或Apple条款不兼容的技术解决方案,也可以使用 专用API LSApplicationWorkspace: openApplicationWithBundleID
。尝试这样的事情:
创建一个.h文件,并设置一个LSApplicationWorkspace
类的接口,并列出所需的方法。您需要在桥接标头中#import "PrivateHeaders.h"
。
//
// PrivateHeaders.h
//
#ifndef PrivateHeaders_h
#define PrivateHeaders_h
@interface LSApplicationWorkspace : NSObject
- (bool)openApplicationWithBundleID:(id)arg1;
@end
#endif /* PrivateHeaders_h */
然后,您应该能够调用此函数并将应用程序的捆绑标识符作为字符串传递。
//
// SomeClass.swift
//
import MobileCoreServices
let workspace = LSApplicationWorkspace()
/**
Launch an App given its bundle identifier
- parameter bundleIdentifier: The bundle identifier of the app to launch
- returns: True if app is launched, otherwise false
*/
func openApp(withBundleIdentifier bundleIdentifier: String) -> Bool {
// Call the Private API LSApplicationWorkspace method
return workspace.openApplication(withBundleID: bundleIdentifier)
}
原始
:您正在做的事情很可能违反了iOS Human Interface Guidelines(尽管不再专门定义“不要以编程方式退出”),因此正如评论所说,它不适合App Store 。无论如何,一旦您的应用以这种方式挂起,我不希望有一种以编程方式恢复它的方法,除非您可以加入Background Operation来运行URLSessionTask.resume
,但我尚未测试它并不确定它是否可以工作。
可以使用Custom URL Scheme或通过Push Notification以编程方式从另一个应用程序或今天的扩展程序中启动应用程序(并因此使其成为前台)。由于该应用程序是UIKit框架的一部分,因此无法通过URL方案从“后台操作”启动该应用程序,该应用程序必须在主线程中运行。
总而言之,我认为您最好的选择是尝试使用通知。这只是意味着用户将需要单击通知以将您的应用重新显示为前台。
答案 1 :(得分:1)
关闭/打开应用程序应由用户明确完成。 Apple不支持其他任何关闭或打开应用程序的方式,并且在上传到应用程序商店时将被拒绝。 iOS人机界面指南指出:
不要以编程方式退出
从不退出iOS应用程序 以编程方式进行,因为人们倾向于将其解释为崩溃。 但是,如果外部环境阻止您的应用程序 能否按预期运行,您需要告诉用户有关 情况并说明他们可以采取的措施。取决于如何 严重的应用程序故障是,您有两种选择。
*显示 精美的屏幕描述了问题并提出了建议 更正。屏幕提供反馈,使用户放心 您的应用程序没有任何问题。让用户掌控一切 让他们决定是否要采取纠正措施,以及 继续使用您的应用程序或按“主页”按钮并打开一个 不同的应用程序
*如果仅某些应用程序功能是 无效时,当人们激活时显示屏幕或警报 功能。仅在人们尝试访问警报时显示警报 功能不正常
答案 2 :(得分:0)
作为约旦出色回答的后续,我想解释一下为什么您的代码首先起作用,以及为什么仅此原因会使您的应用程序被拒绝,即使没有任何功能使其再次激活并将其带入前景。
正如maddy在评论中指出的那样,您基本上是从UIApplication
的私有API调用方法。这是由于Objective-C运行时的动态链接而起作用的。您可能会想:“但是我正在使用Swift,这与Objective-C有什么关系?”答案在于#selector
机制。选择器基本上只是一个象征,Objective-C运行时在表中查找以获取其调用的方法(为您服务)。这就是为什么在进行类似myObjectInstance.someMethod()
之类的事情时说“调用方法”在技术上是不正确的原因。正确的措辞方式是向对象“发送消息”,因为这就是运行时中发生的事情。目标行动机制就是以此为基础的。 sendAction(_: Selector?, to: Any?)
方法执行相同的操作。因此,实际上您的代码执行以下操作:
URLSessionTask
的{{1}}方法相对应的符号。suspend()
的{{1}}实例,以调用 对该符号具有的方法。现在通常会导致崩溃,并出现典型的“未知选择器已发送至实例...”错误消息。但是在这里,肯定是巧合的shared
也有一个用于该实例的方法(或者,运行时在其表中也为该符号列出了其方法之一)。您可以“找到”未在其公共头文件中声明的方法。您已成功规避了对此的编译时检查,并调用了 private API 的一部分的方法。 Apple Developer Program License Agreement
除此之外,我强烈建议不要首先尝试以这种方式设计应用程序。正如玛迪指出的那样,也有可能认为它违反了HIG。即使您不打算进行任何恶意操作并在应用程序的描述中正确解释该功能,也不会使Apple让它滑动(我认为)。就用户而言,如果应用程序做了某些事情,而系统已经以不同的方式针对特定机制(至少就应用程序的背景和前景而言),我也会感到烦恼。
答案 3 :(得分:-1)
我认为没有用户交互就无法完成
该选项是您可以生成推送通知,以告知用户将应用程序置于前台
当操作系统传递推送通知并且目标应用程序未在前台运行时,它将显示通知。
如果存在通知警报,并且用户点击或单击操作按钮(或移动操作滑块),则应用程序将启动并调用方法以传递本地通知对象或远程通知有效内容。