[ios] 푸시 알림에서 앱이 시작 / 열렸는지 감지

푸시 알림에서 앱이 시작 / 열렸는지 알 수 있습니까?

시작 이벤트가 여기에서 잡힐 수 있다고 생각합니다.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    if (launchOptions != nil) {
         // Launched from push notification
         NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];

    }
}

그러나 앱이 백그라운드에있을 때 푸시 알림에서 앱이 열려 있는지 어떻게 알 수 있습니까?



답변

이 코드를 참조하십시오 :

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    if ( application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground  )
    {
         //opened from a push notification when the app was on background
    }
}

와 동일

-(void)application:(UIApplication *)application didReceiveLocalNotification (UILocalNotification *)notification


답변

늦었지만 아마도 유용

앱이 실행되고 있지 않을 때

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

..

푸시 알림을 확인해야하는 곳

NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notification) {
    NSLog(@"app recieved notification from remote%@",notification);
    [self application:application didReceiveRemoteNotification:notification];
} else {
    NSLog(@"app did not recieve notification");
}


답변

우리가 겪었던 문제는 앱이 시작된 후 뷰를 올바르게 업데이트하는 것이 었습니다. 여기에는 복잡한 라이프 사이클 방법 시퀀스가 ​​혼동됩니다.

수명주기 방법

iOS 10 테스트에서 다양한 사례에 대해 다음과 같은 일련의 수명주기 방법이 밝혀졌습니다.

DELEGATE METHODS CALLED WHEN OPENING APP

Opening app when system killed or user killed
    didFinishLaunchingWithOptions
    applicationDidBecomeActive

Opening app when backgrounded
    applicationWillEnterForeground
    applicationDidBecomeActive

DELEGATE METHODS WHEN OPENING PUSH

Opening push when system killed
    [receiving push causes didFinishLaunchingWithOptions (with options) and didReceiveRemoteNotification:background]
    applicationWillEnterForeground
    didReceiveRemoteNotification:inactive
    applicationDidBecomeActive

Opening push when user killed
    didFinishLaunchingWithOptions (with options)
    didReceiveRemoteNotification:inactive [only completionHandler version]
    applicationDidBecomeActive

Opening push when backgrounded
    [receiving push causes didReceiveRemoteNotification:background]
    applicationWillEnterForeground
    didReceiveRemoteNotification:inactive
    applicationDidBecomeActive

문제

이제 우리는 다음을 수행해야합니다.

  1. 사용자가 푸시에서 앱을 여는 지 확인
  2. 푸시 상태를 기반으로 뷰 업데이트
  3. 후속 열기가 사용자를 동일한 위치로 되 돌리지 않도록 상태를 지우십시오.

까다로운 점은 응용 프로그램이 실제로 활성화 될 때보기를 업데이트해야한다는 것입니다. 이는 모든 경우에 동일한 수명주기 방법입니다.

솔루션 스케치

솔루션의 주요 구성 요소는 다음과 같습니다.

  1. notificationUserInfoAppDelegate에 인스턴스 변수를 저장하십시오 .
  2. 설정 notificationUserInfo = nil모두 applicationWillEnterForegrounddidFinishLaunchingWithOptions.
  3. 설정 notificationUserInfo = userInfo에서didReceiveRemoteNotification:inactive
  4. 에서 applicationDidBecomeActive항상 사용자 정의 메소드를 호출 openViewFromNotification하고 전달하십시오 self.notificationUserInfo. self.notificationUserInfonil 인 경우 일찍 반환하고, 그렇지 않으면의 알림 상태에 따라보기를 엽니 다 self.notificationUserInfo.

설명

푸시에서 열거 didFinishLaunchingWithOptionsapplicationWillEnterForeground항상 바로 직전에 호출되면 먼저 didReceiveRemoteNotification:inactive이러한 메소드에서 notificationUserInfo를 재설정하여 오래된 상태가 없도록합니다. 그런 다음 didReceiveRemoteNotification:inactive호출 되면 푸시에서 여는 것을 알고 있으므로 사용자를 올바른 뷰로 전달하기 위해 self.notificationUserInfo선택합니다 applicationDidBecomeActive.

사용자가 앱 스위처 내에서 앱을 연 경우 (즉, 앱이 포 그라운드에있는 동안 홈 버튼을 두 번 두드리는 경우) 푸시 알림을받는 경우가 마지막입니다. 이 경우에만 didReceiveRemoteNotification:inactive호출되며 WillEnterForeground와 didFinishLaunching도 호출되지 않으므로 해당 상황을 처리하기 위해 특별한 상태가 필요합니다.

도움이 되었기를 바랍니다.


답변

이것은 잘 착용 된 게시물입니다 …하지만 여전히 다양한 의견에서 지적한 것처럼 문제에 대한 실제 해결책 이 누락되었습니다 .

원래 질문은 푸시 알림에서 앱이 언제 시작
/ 열렸 는지 감지하는 것입니다 ( 예 : 사용자가 알림을 탭함). 실제로이 사례에 대한 답변은 없습니다.

알림이 도착하면 통화 흐름에서 이유를 확인할 수 있습니다. application:didReceiveRemoteNotification...

통지가 수신 될 때 호출되는 통지는 사용자가 탭하면 다시. 이 때문에 UIApplicationState사용자가 탭을 보았을 때 알 수 없습니다 .

또한 iOS 9 이상 (아마도 8)에서 시작한 후 다시 호출 되는 application:didFinishLaunchingWithOptions...것처럼 앱의 ‘콜드 스타트’상황을 더 이상 처리 할 필요가 없습니다 application:didReceiveRemoteNotification....

그렇다면 사용자 탭이 이벤트 체인을 시작했는지 어떻게 알 수 있습니까? 내 해결책은 앱이 백그라운드 또는 콜드 스타트에서 나오기 시작하는 시간을 표시 한 다음 그 시간을 확인하는 것입니다 application:didReceiveRemoteNotification.... 0.1 초 미만이면 탭이 스타트 업을 트리거했는지 확인할 수 있습니다.

스위프트 2.x

class AppDelegate: UIResponder, UIApplicationDelegate {

  var wakeTime : NSDate = NSDate()        // when did our application wake up most recently?

  func applicationWillEnterForeground(application: UIApplication) {
    // time stamp the entering of foreground so we can tell how we got here
    wakeTime = NSDate()
  }

  func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
    // ensure the userInfo dictionary has the data you expect
    if let type = userInfo["type"] as? String where type == "status" {
      // IF the wakeTime is less than 1/10 of a second, then we got here by tapping a notification
      if application.applicationState != UIApplicationState.Background && NSDate().timeIntervalSinceDate(wakeTime) < 0.1 {
        // User Tap on notification Started the App
      }
      else {
        // DO stuff here if you ONLY want it to happen when the push arrives
      }
      completionHandler(.NewData)
    }
    else {
      completionHandler(.NoData)
    }
  }
}

스위프트 3

class AppDelegate: UIResponder, UIApplicationDelegate {

    var wakeTime : Date = Date()        // when did our application wake up most recently?

    func applicationWillEnterForeground(_ application: UIApplication) {
      // time stamp the entering of foreground so we can tell how we got here
      wakeTime = Date()
    }

  func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

      // ensure the userInfo dictionary has the data you expect
      if let type = userInfo["type"] as? String, type == "status" {
        // IF the wakeTime is less than 1/10 of a second, then we got here by tapping a notification
        if application.applicationState != UIApplicationState.background && Date().timeIntervalSince(wakeTime) < 0.1 {
          // User Tap on notification Started the App
        }
        else {
          // DO stuff here if you ONLY want it to happen when the push arrives
        }
        completionHandler(.newData)
      }
      else {
        completionHandler(.noData)
      }
    }
}

iOS 9 이상에서 두 가지 경우 (백그라운드의 앱, 실행되지 않는 앱)에 대해 이것을 테스트했으며 매력처럼 작동합니다. 0.1도 상당히 보수적이며 실제 값은 ~ 0.002s이므로 0.01도 좋습니다.


답변

앱이 종료되고 사용자가 푸시 알림을 탭하면

public func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
   if launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] != nil {
      print("from push")
    }
}

앱이 백그라운드에 있고 사용자가 푸시 알림을 탭하면

사용자가 시스템 표시 알림에서 앱을 열면 앱이 포 그라운드로 진입하려고 할 때 시스템이이 메소드를 다시 호출 하여 사용자 인터페이스를 업데이트하고 알림과 관련된 정보를 표시 할 수 있습니다.

public func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
  if application.applicationState == .inactive {
    print("from push")
  }
}

앱에 따라 content-availableinside로 자동 푸시를 보낼 수도 aps있으므로 다음 사항도 알고 있어야합니다. https : //.com/a/33778990/1418457 참조


답변

‘비 실행’상태의 Swift 2.0 (로컬 및 원격 알림)

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {


// Handle notification
if (launchOptions != nil) {

    // For local Notification
    if let localNotificationInfo = launchOptions?[UIApplicationLaunchOptionsLocalNotificationKey] as? UILocalNotification {

        if let something = localNotificationInfo.userInfo!["yourKey"] as? String {
            self.window!.rootViewController = UINavigationController(rootViewController: YourController(yourMember: something))
        }


    } else

    // For remote Notification
    if let remoteNotification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as! [NSObject : AnyObject]? {

        if let something = remoteNotification["yourKey"] as? String {
            self.window!.rootViewController = UINavigationController(rootViewController: YourController(yourMember: something))
        }
    }

}


return true
}


답변

에서 application:didReceiveRemoteNotification:앱이 전경 또는 배경에있을 때 체크 당신은 통지를받은 여부.

백그라운드에서 수신 한 경우 알림에서 앱을 시작합니다.

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
        NSLog(@"Notification received by running app");
    } else {
        NSLog(@"App opened from Notification");
    }
}