ios 앱에서 firebase를 이용해서 notification 작업을 수행하는 경우. 매 기기마다 주어지는 registration id를 이용해서 각각의 기기에 push notification을 보내게된다. 이 id는 기기에서 앱이 시작될때마다 MessagingDelegate의  messaging:didReceiveRegistrationToken이 호출되고 id를 얻을수 있게 된다. 또 새로운 id가 주어진경우에도 이 함수가 호출된다. 사용자가 이미 sign in되어있는 상황에서는 sign in 과정을 거치지 않고 bypass 되므로 이경우 위해 didReceiveRegistrationToken 내에서 registration id을 저장하는 작업을 수행해야 한다.또 sign in 되어있지 않아서 sign in 과정을 거쳐야 하는 경우를 위해서 sign in 과정에서도 registration id를 저장하는 작업을 수행해 주어야 한다. 이때는 

InstanceID.instanceID().instanceID { (result, error) in
 if let error = error {
   print("Error fetching remote instange ID: (error)")
 } else if let result = result {
   print("Remote instance ID token: (result.token)")
   self.instanceIDTokenMessage.text  = "Remote InstanceID token: (result.token)"
 }
}

와 같이 registration id (위의 코드에서 result.token)에 접근가능하다.

내가 정리한내용

firebase cloud messaging에서 각각의 기기에 메시지를 보녀려 하는 경우 각각의 기기는 registration token(registration id)를 통해 각각은 구별되면 메시지를 보낼수 있게 된다.

 ios에서는 두가지의 notification이 있는데 하나는 local notification또하나는 push notification이다. 

ios notification은 content, trigger, request로 구성된다. content는 title, body, sound등을 가진다. trigger는 시간,지역 등등에 의해 trigger된다.



firebase cloud messaging을 위한 기본 정보

https://firebase.google.com/docs/cloud-messaging/admin/send-messages

ios device에서 registration token을 얻는 방법 (registration id 는 registration token이라고 불리기도 한다.)

https://firebase.google.com/docs/cloud-messaging/ios/client

https://firebase.google.com/docs/cloud-messaging/ios/client#access_the_registration_token

firebase authenticatoin을 이용하는 경우 registration token 관리방법

https://stackoverflow.com/a/47066493

This is not supported out of the box but you can build the mechanism. You need to maintain a uidspecific deviceGroup and all the registration ID per device that belongs to it.

Each time a user signs in with Firebase, you get the device registration ID and the user’s ID token and send it to your backend. You verify the ID token and get the uid from it, you then add that registration ID to that user’s device group.

Each time a user signs out, you remove their registration ID from the signed out user’s device group.

When you want to send a push notification to a specified user, you can send it to the user’s device group ID.

This is the simplified version but there are a bunch of edge cases you have to deal with to keep the device group for a user in sync so no notification is sent to a signed out user.

https://stackoverflow.com/a/47430551

A user may be using multiple devices. You should expect this to be the case. You’ll need to store each device token for all devices that a particular user may be using in order to notify them. Typically, Firebase apps will use Realtime Database to record the token at the time of login.

firebase facebook, google auth를 사용하는 경우

Auth.auth().signInAndRetrieveData(with: fbCredential) { (user, error) in … }

Auth.auth().signInAndRetrieveData(with: googleAuthCredential) { (user, error) in …}

의 형태가 되며 sign in이 성공적으로 이루어지고 user ( FIRAuthDataResult obj )를 되돌려 받게된다. 이 FIRAuthDataResult 안에는 user property와 additionalUserInfo property가 들어 있다. 이를 통해서는 registration id를 얻을수 없다. 다만 additionalUserInfo안에 newUser를 통해 처음가입하는 유저인지 알수는 있다.

FIRAuthDataResult ref) https://firebase.google.com/docs/reference/ios/firebaseauth/api/reference/Classes/FIRAuthDataResult#/c:objc(cs)FIRAuthDataResult(py)user

registration id 얻는방법

https://stackoverflow.com/a/41523085

https://firebase.google.com/docs/cloud-messaging/ios/client

The tokenRefreshNotification function doesn’t always get called when launching the app.

However, when placing the code inside the regular didRegisterForRemoteNotificationsWithDeviceToken delegate function, I can get the token every time:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    if let refreshedToken = InstanceID.instanceID().token() {
        print("InstanceID token: (refreshedToken)")
    }
}

(Swift 3 + Firebase 4.0.4)

firebase cloud messaging client app in ios

https://firebase.google.com/docs/cloud-messaging/ios/client

For iOS client apps, you can implement Firebase Cloud Messaging in two complementary ways:

  • Receive basic push messages up to 4KB over the Firebase Cloud Messaging APNs interface.
  • Send messages upstream and/or receive downstream data payloads up to 4KB in foregrounded apps.

To write your client code in Objective-C or Swift, we recommend that you use the FIRMessaging API. The quickstart example provides sample code for both languages.

Method swizzling in Firebase Cloud Messaging

The FCM SDK performs method swizzling in two key areas: mapping your APNs token to the FCM registration token and capturing analytics data during downstream message callback handling. Developers who prefer not to use swizzling can disable it by adding the flag FirebaseAppDelegateProxyEnabled in the app’s Info.plist file and setting it to NO (boolean value). Relevant areas of the guides provide code examples, both with and without method swizzling enabled.

Important: With the Firebase Unity SDK on iOS, do not disable method swizzling. Swizzling is required by the SDK, and without it key Firebase features such as FCM token handling do not function properly.

Add Firebase to your iOS project

This section covers tasks you may have completed if you have already enabled other Firebase features for your app. For FCM specifically, you’ll need to upload your APNs authentication key andregister for remote notifications.

Prerequisites

Before you begin, you need a few things set up in your environment:

  • Xcode 9.2 or later
  • An Xcode project targeting iOS 8 or above
  • Swift projects must use Swift 3.0 or later
  • The bundle identifier of your app
  • CocoaPods 1.4.0 or later
  • For Cloud Messaging:
  • A physical iOS device
  • An Apple Push Notification Authentication Key for your Apple Developer account
  • In Xcode, enable Push Notifications in App > Capabilities

If you don’t have an Xcode project already, you can download one of our quickstart samples if you just want to try a Firebase feature. If you’re using a quickstart, remember to get the bundle identifier from the project settings, you’ll need it for the next step.

Xcode 8 support deprecated: In May this year Apple announced that

starting July 2018, all iOS apps submitted to the App Store must be built with the iOS 11 SDK

included in Xcode 9. When this date passes, updates to the Firebase iOS SDKs will no longer support Xcode 8.Support for iOS 7 removed: As of v5.0.0 of the Firebase SDK for iOS, support for iOS 7 is removed. Upgrade your apps to target iOS 8 or above. To see the breakdown of worldwide iOS versions,

go to Apple’s App Store support page

.Add Firebase to your app

It’s time to add Firebase to your app. To do this you’ll need a Firebase project and a Firebase configuration file for your app.

To create a Firebase project:

image

Firebase automatically assigns a unique ID to your Firebase project. This identifier displays in publicly visible Firebase services, for example:

  • Default database URL — your-project-id.firebaseio.com
  • Default hosting subdomain — your-project-id.firebaseapp.com

Follow the remaining setup steps, then click Create project (or Add Firebase, if you’re using an existing Google project).

Firebase automatically provisions resources for your Firebase project. The process typically takes a few minutes. When the process completes, you’ll be taken to the overview page for your Firebase project in the Firebase console.

Now that you have a project, you can add your iOS app to it:

  1. Click Add Firebase to your iOS app and follow the setup steps. If you’re importing an existing Google project, this may happen automatically and you can just download the config file.
  2. When prompted, enter your app’s bundle ID. It’s important to enter the bundle ID your app is using; this can only be set when you add an app to your Firebase project.
  3. During the process, you’ll download a GoogleService-Info.plist file. You can download this file again at any time.
  4. After you add the initialization code, run your app to send verification to the Firebase console that you’ve successfully installed Firebase.

Note: If you have multiple build variants with different bundle IDs defined, each app must be added to your project in Firebase console.Add the SDK

If you are setting up a new project, you need to install the SDK. You may have already completed this as part of creating a Firebase project.

We recommend using CocoaPods to install the libraries. You can install Cocoapods by following the installation instructions. If you’d rather not use CocoaPods, you can integrate the SDK frameworks directly without using CocoaPods.

If you are planning to download and run one of the quickstart samples, the Xcode project and Podfile are already present, but you’ll still need to install the pods and download the GoogleService-Info.plist file. If you would like to integrate the Firebase libraries into one of your own projects, you will need to add the pods for the libraries that you want to use.

image

Note: If you have multiple bundle IDs in your project, each bundle ID must be connected in Firebase console so it can have its own

GoogleService-Info.plist

file.Upload your APNs authentication key

Upload your APNs authentication key to Firebase. If you don’t already have an APNs authentication key, see Configuring APNs with FCM.

  1. Inside your project in the Firebase console, select the gear icon, select Project Settings, and then select the Cloud Messaging tab.
  2. In APNs authentication key under iOS app configuration, click the Upload button.
  3. Browse to the location where you saved your key, select it, and click Open. Add the key ID for the key (available in Certificates, Identifiers & Profiles in the Apple Developer Member Center) and click Upload.


위의 과정을 보여주는 동여상 

https://www.youtube.com/watch?v=QwolFT5QSk0

https://www.youtube.com/watch?v=LBw5tuTvKd4

Initialize Firebase in your app

You’ll need to add Firebase initialization code to your application. Import the Firebase module and configure a shared instance as shown:

  1. Import the Firebase module in your UIApplicationDelegate:
  2. Configure a FirebaseApp shared instance, typically in your application’s application:didFinishLaunchingWithOptions: method:
import Firebase
// Use Firebase library to configure APIs
FirebaseApp.configure()

Register for remote notifications Either at startup, or at the desired point in your application flow, register your app for remote notifications. Call

registerForRemoteNotifications

as shown:

if #available(iOS 10.0, *) {
 // For iOS 10 display notification (sent via APNS)
 UNUserNotificationCenter.current().delegate = self

 let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
 UNUserNotificationCenter.current().requestAuthorization(
   options: authOptions,
   completionHandler: {_, _ in })
} else {
 let settings: UIUserNotificationSettings =
 UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
 application.registerUserNotificationSettings(settings)
}

application.registerForRemoteNotifications()
AppDelegate.swift

for devices running iOS 10 and above, you must assign your delegate object to the

UNUserNotificationCenter

object to receive display notifications, and the

FIRMessaging

object to receive data messages, before your app finishes launching. For example, in an iOS app, you must assign it in the

applicationWillFinishLaunching:

or

applicationDidFinishLaunching:

method.

Access the registration token

(registration id 는 registration token이라고 불리기도 한다.)

By default, the FCM SDK generates a registration token for the client app instance on app launch. Similar to the APNs device token, this token allows you to send targeted notifications to any particular instance of your app.

In the same way that iOS typically delivers an APNs device token on app start, FCM provides a registration token via MessagingDelegate’s messaging:didReceiveRegistrationToken:method. The FCM SDK retrieves a new or existing token during initial app launch and whenever the token is updated or invalidated. In all cases, the FCM SDK calls messaging:didReceiveRegistrationToken: with a valid token.

The registration token may change when:

  • The app is restored on a new device
  • The user uninstalls/reinstall the app
  • The user clears app data.

Set the messaging delegate

To receive registration tokens, implement the messaging delegate protocol and set Messaging’s delegate property after calling [FIRApp configure]. For example, if your application delegate conforms to the messaging delegate protocol, you can set the delegate on application:didFinishLaunchingWithOptions: to itself.

Messaging.messaging().delegate = self

Fetching the current registration token

Registration tokens are delivered via the method messaging:didReceiveRegistrationToken:. This method is called generally once per app start with registration token. When this method is called, it is the ideal time to:

  • If the registration token is new, send it to your application server.
  • Subscribe the registration token to topics. This is required only for new subscriptions or for situations where the user has re-installed the app.

You can retrieve the token directly using instanceIDWithHandler:. This callback provides an InstanceIDResult, which contains the token. A non null error is provided if the InstanceID retrieval failed in any way.

InstanceID.instanceID().instanceID { (result, error) in
 if let error = error {
   print("Error fetching remote instange ID: (error)")
 } else if let result = result {
   print("Remote instance ID token: (result.token)")
   self.instanceIDTokenMessage.text  = "Remote InstanceID token: (result.token)"
 }
}

Generally, the token is available locally, so this method does not open a network connection. You can use this method at any time to access the token instead of storing it.

Avoid calling

.getToken(authorizedEntity,scope)

unless there is a need to enable multiple senders. Use

instanceIDWithHandler:

instead.Monitor token refresh

To be notified whenever the token is updated, supply a delegate conforming to the messaging delegate protocol. The following example registers the delegate and adds the proper delegate method:

func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
 print("Firebase registration token: (fcmToken)")

 let dataDict:[String: String] = ["token": fcmToken]
 NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
 // TODO: If necessary send token to application server.
 // Note: This callback is fired at each app startup and whenever a new token is generated.
}AppDelegate.swift

Alternatively, you can listen for an NSNotification namedkFIRMessagingRegistrationTokenRefreshNotification rather than supplying a delegate method. The token property always has the current token value.

Swizzling disabled: mapping your APNs token and registration token

If you have disabled method swizzling, you’ll need to explicitly map your APNs token to the FCM registration token. Override the methods didRegisterForRemoteNotificationsWithDeviceTokento retrieve the APNs token, and then set FIRMessaging’s APNSToken property:

func application(application: UIApplication,
                didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
 Messaging.messaging().apnsToken = deviceToken
}

After the FCM registration token is generated, you can access it and listen for refresh events using the same methods as with swizzling enabled.

Import existing user APNs tokens

If you have an existing user base that you want to onboard to an FCM client app, use the batchImportAPI provided by Instance ID. With this API, you can bulk import existing iOS APNs tokens into FCM, mapping them to new, valid registration tokens.

Prevent auto initialization

FCM generates an Instance ID, which is used as a registration token within FCM. When an Instance ID is generated the library will upload the identifier and configuration data to Firebase.If you want to get an explicit opt-in before using Instance ID, you can prevent generation at configure time by disabling FCM. To do this, add a metadata value to your Info.plist (not your GoogleService-Info.plist):

FirebaseMessagingAutoInitEnabled = NO

To re-enable FCM, you can make a runtime call:

Messaging.messaging().autoInitEnabled = true

This value persists across app restarts once set.

junecnol:

firebase cloud function basic “hello world”

my review point is 9 

firebase init

firebase deploy

getting a function endpoint link

다음 비디오 :  https://youtu.be/nezhsGvrhaI

여기에서는 console log에 출력, 확인하는 방법, query string을 request에 포함하는 방법

firebase remote notification


https://youtu.be/LBw5tuTvKd4?t=83     project에서 사용할 기능을 설정하는 작업 ( push notification기능 설정하기 )

https://youtu.be/LBw5tuTvKd4?t=350     apple account에서 project가 push notification을 사용할수 있게 설정한다

https://youtu.be/LBw5tuTvKd4?t=383     create certificates and export

https://youtu.be/LBw5tuTvKd4?t=500     upload certificates into firebase

참고 링크 : 

https://developer.android.com/training/scheduling/alarms.html

http://droidmentor.com/schedule-notifications-using-alarmmanager/

AlarmManager를 이용한 작업 (jobscheduler를 이용한 경우도 같음) 은 기기가 reboot되면 스케쥴해놓은 것이 사라진다. 그러므로 reboot시 재등록을 하는 작업이 필요하다. 

재등록 manifest의 예시

<uses-permission android:name=“android.permission.RECEIVE_BOOT_COMPLETED”/>

<application>
<!– Register the Alarm Receiver –>
<receiver android:name=“.AlarmReceiver”
          android:enabled=“false”>
    <intent-filter>
        <action android:name=“android.intent.action.BOOT_COMPLETED” />
    </intent-filter>
</receiver>
<application>

재등록의 코드 예시 (broadcast receiver에 의해 수행된다. )

public class AlarmReceiver extends BroadcastReceiver {

   String TAG = “AlarmReceiver”;

   @Override
   public void onReceive(Context context, Intent intent) {

                // 이부분에서 alarmmanager 재시작

   }

}

알람생성 예시

Intent intent1 = new Intent(context, cls);
       PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
                 DAILY_REMINDER_REQUEST_CODE, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
       AlarmManager am = (AlarmManager) context.getSystemService(ALARM_SERVICE);
       am.cancel(pendingIntent);
       pendingIntent.cancel();

intent의 타깃 class(위의 예시에서는 cls)는 정해진 알람에 따라 수행된다.

알람의 정해진 시기에 따라 수행될 작업은 broadcast receiver에서 수행된다. 

알람 수행 receiver 예시 코드

public class AlarmReceiver extends BroadcastReceiver {

   String TAG = “AlarmReceiver”;

   @Override
   public void onReceive(Context context, Intent intent) {
       //Trigger the notification
        // 이부분에서 notification을 만들고 발생한다.
   }
}