FCM Firebase cloud message

1 篇文章 / 0 new
author
FCM Firebase cloud message
► API 註冊與取得相關 key
前往  FireBase 登入, 並建立專案以取得相關所需 key
► 需要套件
android-support-annotations.jar,android-support-compat.jar,android-support-core-ui.jar,android-support-core-utils.jar,android-support-fragment.jar,android-support-media-compat.jar,android-support-v4.jar,google-firebase-common.jar,google-firebase-iid.jar,google-firebase-messaging.jar,google-play-services-basement.jar(含res),google-play-services-tasks.jar
Android Studio 提供引入為 aar, Eclipse 可至網站下載相關jar,下載 Google Firebase libraries for Eclipse 
► 權限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission android:name="tw.shioulo.fcm.test.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="PackageName.permission.C2D_MESSAGE" />
► 相關宣告
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver"
    android:exported="true" android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
            <category android:name="PackageName" />
        </intent-filter>
</receiver>
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:exported="true" />
    <meta-data android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />
<service
    android:name=".MyFirebaseMessagingService">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
</service>
<service
    android:name=".MyFirebaseInstanceIDService">
    <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
    </intent-filter>
</service>
► 程式
初始化
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //
    if (getIntent().getExtras() != null) {
        for (String key : getIntent().getExtras().keySet()) {
            Object value = getIntent().getExtras().get(key);
            Log.d("dd", "Key: " + key + " Value: " + value);
        }
    }
    //參數資料來自 firebase 後台的 <strong>google-services.json</strong>
    if(FirebaseApp.getApps(this).isEmpty()) {
        FirebaseOptions.Builder builder = new FirebaseOptions.Builder();
        builder.setApiKey("AIzaSyD88cqipxxxxxTop_0f03gjPExxxxxxV5Lk");//client/api_key/current_key
        builder.setApplicationId("1:814xxxxxx498:android:9f8d7fxxxxxxeb6c8");//client/client_info/mobilesdk_app_id
        builder.setDatabaseUrl("https://fcm-xxxxxx.firebaseio.com");//project_info/firebase_url
        builder.setGcmSenderId("8145xxxxxx98");//project_info/project_number
        builder.setStorageBucket("fcm-xxxxxx.appspot.com");//project_info/storage_bucket
        FirebaseOptions options = builder.build();
        FirebaseApp.initializeApp(this, options);
    }
    String refreshedToken = FirebaseInstanceId.getInstance().getToken();
    Log.d("dd","Token:"+refreshedToken);
}
 
MyFirebaseInstanceIDService 當token初次產生或異動時觸發
import android.util.Log;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.FirebaseInstanceIdService;
 
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
    /**
     * Called if InstanceID token is updated. This may occur if the security of
     * the previous token had been compromised. Note that this is called when the InstanceID token
     * is initially generated so this is where you would retrieve the token.
     */
    // [START refresh_token]
    @Override
    public void onTokenRefresh() {
        // Get updated InstanceID token.
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
        Log.d("dd", "[Refreshed token]: " + refreshedToken);
 
        // If you want to send messages to this application instance or
        // manage this apps subscriptions on the server side, send the
        // Instance ID token to your app server.
        sendRegistrationToServer(refreshedToken);
    }
    // [END refresh_token]
    /**
     * Persist token to third-party servers.
     *
     * Modify this method to associate the user's FCM InstanceID token with any server-side account
     * maintained by your application.
     */
    private void sendRegistrationToServer(String token) {
        // TODO: Implement this method to send token to your app server.
    }
}
MyFirebaseMessagingService 收到推播訊息時觸發, 但又會因訊息格式及app是否處於前景狀態而有所差異
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
 
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
 
public class MyFirebaseMessagingService extends FirebaseMessagingService {
 
    private static final String TAG = "dd";
 
    //Called when message is received.
    // [START receive_message]
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // [START_EXCLUDE]
        // There are two types of messages data messages and notification messages. Data messages are handled
        // here in onMessageReceived whether the app is in the foreground or background. Data messages are the type
        // traditionally used with GCM. Notification messages are only received here in onMessageReceived when the app
        // is in the foreground. When the app is in the background an automatically generated notification is displayed.
        // When the user taps on the notification they are returned to the app. Messages containing both notification
        // and data payloads are treated as notification messages. The Firebase console always sends notification
        // messages. For more see: https://firebase.google.com/docs/cloud-messaging/concept-options
        // [END_EXCLUDE]
 
        // Handle FCM messages here.
        // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
        Log.d(TAG, "[From]: " + remoteMessage.getFrom());
 
        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
            Log.d(TAG, "[Message data]: " + remoteMessage.getData());
            String data = remoteMessage.getData().get("message");
 
            if (/* Check if data needs to be processed by long running job */ true) {
                // For long-running tasks (10 seconds or more) use Firebase Job Dispatcher.
                //scheduleJob();
            } else {// Handle message within 10 seconds
                handleNow();
            }
        }
 
        // Check if message contains a notification payload.
        if (remoteMessage.getNotification() != null) {
            RemoteMessage.Notification noti = remoteMessage.getNotification();
            String body = noti.getBody();
            String title = noti.getTitle();
            Log.d(TAG, "[Message Notification]:  Body=" + noti.getBody());
            //sendNotification(title, body);
        }
 
        // Also if you intend on generating your own notifications as a result of a received FCM
        // message, here is where that should be initiated. See sendNotification method below.
    }
    // [END receive_message]
 
    //Handle time allotted to BroadcastReceivers.
    private void handleNow() {
        Log.d(TAG, "Short lived task is done.");
    }
 
    //Create and show a simple notification containing the received FCM message.
    private void sendNotification(String title, String messageBody) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent, PendingIntent.FLAG_ONE_SHOT);
        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_launcher)
                .setContentTitle(title)
                .setContentText(messageBody)
                .setAutoCancel(true)
                //.setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }
}
► PHP Server
#API access key from Google API's Console
$id = 'eYyA5XLg.................................eIvsiTPil4OOJD';
// API access key from Google API's Console
define( 'API_ACCESS_KEY', 'AAAAvans6KI:APA91......................SBB8VgU' );
$registrationIds = array($id); //$id is string not array
// prep the bundle
//讓 android 主動發出通知訊息用
$notification = array
(
    'title' => '標題title', 'body' => '內容body', 'icon' => 'logo',
    'sound' => 'default', 'tag' => 'tag', 'color' => '#ffffff'
);
//資料格式自定義
$data = array
(
    'message' => 'message body',
    'click_action' => "PUSH_INTENT"
);
$fields = array
(
    'registration_ids'  => $registrationIds,
    'notification'      => $notification,
    'data'              => $data,
    'priority'          => 'normal'
);
$headers = array
(
    'Authorization: key=' . API_ACCESS_KEY,
    'Content-Type: application/json'
);
 
$ch = curl_init();
curl_setopt( $ch,CURLOPT_URL, 'https://fcm.googleapis.com/fcm/send' );
curl_setopt( $ch,CURLOPT_POST, true );
curl_setopt( $ch,CURLOPT_HTTPHEADER, $headers );
curl_setopt( $ch,CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch,CURLOPT_SSL_VERIFYPEER, false );
curl_setopt( $ch,CURLOPT_POSTFIELDS, json_encode( $fields ) );
$result = curl_exec($ch );
curl_close( $ch );
echo $result;
► android 觸發說明
server端推播資料是否包含 'notification' => $notification 這組資料對 android client將有所影響,
當包含
若 app處於背景狀態下, 則系統會主動發出通知訊息告知使用者, 但onMessageReceived()不會觸發, 直到使用者點選訊息啟動 app時則 $data 的資料會封裝在 intent 內供程式讀取.
若 app處於前景狀態下, 系統不會主動發出通知, 但 onMessageReceived()則會被觸發供程式處理.
不包含
則 onMessageReceived()不論 app在前景或背景均會被觸發, 是否發出通知訊息則需自行處理.
Free Web Hosting