# .Net Core 後台FCM推播
###### tags: `.net core` `FCM` `推播`
使用Firebase進行推播,方法相當單純
[chrome推播測試工具](https://github.com/GoogleChrome/chrome-extensions-samples)
[工具使用說明](https://ithelp.ithome.com.tw/articles/10211813)
## 在FireBase上建立專案
https://console.firebase.google.com/
建立好的樣子

## 使用FirebaseAdmin
需安裝套件FirebaseAdmin
https://firebase.google.com/docs/cloud-messaging/send-message?authuser=0#admin_sdk_error_reference
https://github.com/firebase/firebase-admin-dotnet/blob/d44de7bb50bedec5ff1ee5944d7eecd064b068e6/FirebaseAdmin/FirebaseAdmin.Snippets/FirebaseMessagingSnippets.cs#L327-L341
### 啟動FirebaseAdmin
### 建立私鑰
產生私鑰後會下載私鑰的json檔案

### 服務初始化
可在需要時才執行來開啟,此處選擇網站開啟時即啟動(重複啟動會報錯)!
#### Program.cs(.Net 5以下Startup)
```
string path = builder.Environment.ContentRootPath + "firebase-adminsdk.json";
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.FromFile(path),
ServiceAccountId = "firebase-adminsdk-qfvow@fir-test-1c603.iam.gserviceaccount.com",
});
```
### 對單一設備發送請求
```
var message = new Message()
{
Data = new Dictionary<string, string>()
{
{ "score", "850" },
{ "time", "2:45" },
},
Token = "",
};
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message);
```
### 對多個設備發送請求
```
var registrationTokens = new List<string>()
{
"YOUR_REGISTRATION_TOKEN_1",
// ...
"YOUR_REGISTRATION_TOKEN_n",
};
var message = new MulticastMessage()
{
Tokens = registrationTokens,
Data = new Dictionary<string, string>()
{
{ "score", "850" },
{ "time", "2:45" },
},
};
var response = await FirebaseMessaging.DefaultInstance.SendMulticastAsync(message);
```
### 設備主題註冊與取消註冊
```
[HttpPost] //主題註冊
public async Task<string> SubscribeToTopicAsync([FromBody] DeviceRegistrationModel request)
{
var response = await FirebaseMessaging.DefaultInstance.SubscribeToTopicAsync(request.DeviceId, request.Topic);
return response.ToString();
}
[HttpPost] //取消註冊
public async Task<string> UnsubscribeFromTopicAsync([FromBody] DeviceRegistrationModel request)
{
var response = await FirebaseMessaging.DefaultInstance.UnsubscribeFromTopicAsync(request.DeviceId, request.Topic);
return response.ToString();
}
```
### 對主題進行推播
```
var message = new Message()
{
Data = new Dictionary<string, string>()
{
{ "score", "850" },
{ "time", "2:45" },
},
Topic = topic,
};
// Send a message to the devices subscribed to the provided topic.
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message);
```
## 使用FirebaseApi
### 1.點選齒輪進入專案設定

### 2.在雲端通訊建立伺服器金鑰
建立好金鑰之後,伺服器金鑰跟寄件者ID就是我們後端會用到的東西了。

可以將金鑰跟senderId寫入appsetting EX:`_configuration["FCM:SenderId"]`
### 3.後端內容
```
[HttpPost]
public string SendPushNotification([FromBody] NotificationData request)
{
try
{
//FCM伺服器金鑰
string applicationID = "AAAASLO7bNM:APA91bHeSO8oechmbvPkVaIe9_BAAuZsXFax9YK6LH9AJAVS4_LVKyIy0w9xCx1dG-JRdazIjqyu9IjxSMJXorBh-lHPJ7LrpddZT_L65lmNZGy2FFyW6p1TstN1mZ8dVjKWIj4nFRtp";
//SenderId
string senderId = "312253050067";
//Service url
string url = "https://fcm.googleapis.com/fcm/send";
//設備ID
string deviceId = null;
if (request.topic)
deviceId = "/topics/" + request.DeviceId;
else
deviceId = request.DeviceId;
//要推播的資料
var data = new
{
to = deviceId,
notification = new
{
body = request.Body,
title = request.Title,
sound = "Enabled"
},
};
var json = JsonConvert.SerializeObject(data);
Byte[] byteArray = Encoding.UTF8.GetBytes(json);
HttpClient client = new HttpClient();
var httpRequestMessage = new HttpRequestMessage();
httpRequestMessage.Method = HttpMethod.Post;
httpRequestMessage.RequestUri = new Uri(url);
httpRequestMessage.Content = new StringContent(json, Encoding.UTF8, "application/json");
httpRequestMessage.Headers.Add(HttpRequestHeader.ContentType.ToString(), "application/json");
httpRequestMessage.Headers.TryAddWithoutValidation("Authorization",string.Format("key={0}", applicationID));
httpRequestMessage.Headers.TryAddWithoutValidation("Sender", string.Format("id={0}", senderId)); //Sender沒有也沒關係,為了防止之後需要一樣寫出來註記
httpRequestMessage.Headers.Add(HttpRequestHeader.ContentLength.ToString(), byteArray.Length.ToString());
HttpResponseMessage response = client.SendAsync(httpRequestMessage).Result;
if(response.StatusCode == HttpStatusCode.OK)
{
//return "推播成功";
return response.ReasonPhrase.ToString();
}
else
{
return response.ReasonPhrase.ToString();
}
}
catch (Exception ex)
{
Console.WriteLine("{0:s}推播失敗:{1}", DateTime.Now, ex.Message);
return ex.Message;
}
}
```
### Model
```
public class NotificationData
{
public string DeviceId { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public bool topic { get; set; }
}
```