先给出Push Kit(推送服务)官方指南链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/push-kit-guide,把开发准备里面需要做的都做下

如果对 Push Kit 比较陌生,官方也提供了学习的视频和配套的资料,链接:https://developer.huawei.com/consumer/cn/training/course/slightMooc/C101718765607651496
看完了前面的资料,相信你已经对Push Kit有了基本的了解了,下面就进入实战环节。
App 端接入需要做的工作很少,主要就两个步骤:
import { pushService } from '@kit.PushKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit';
export default class EntryAbility extends UIAbility {
// 入参 want 与 launchParam 并未使用,为初始化项目时自带参数
async onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): Promise<void> {
// 获取Push Token
try {
const pushToken: string = await pushService.getToken();
hilog.info(0x0000, 'testTag', 'Succeeded in getting push token');
} catch (err) {
let e: BusinessError = err as BusinessError;
hilog.error(0x0000, 'testTag', 'Failed to get push token: %{public}d %{public}s', e.code, e.message);
}
// 上报Push Token并上报到您的服务端
}
}
import { BusinessError } from '@kit.BasicServicesKit';
import { UIAbility } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { notificationManager } from '@kit.NotificationKit';
class MyAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage) {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
notificationManager.requestEnableNotification(this.context).then(() => {
hilog.info(0x0000, 'testTag', `[ANS] requestEnableNotification success`);
}).catch((err: BusinessError) => {
hilog.error(0x0000, 'testTag', `[ANS] requestEnableNotification failed, code is ${err.code}, message is ${err.message}`);
});
});
}
}
做完这两步就可以收到推送的通知了。这时候点击收到的推送,打开的是 app 的首页,如果想打开其他的界面,可以参考官方文档,链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/push-send-alert#section697519219136
服务端接入也不难,重点就是生成鉴权令牌,鉴权令牌生成的方法可以参考这个链接:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/push-jwt-token#section4780149123414
以 Java 代码示例,项目中先引入需要的maven依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>1.78.1</version>
<scope>runtime</scope>
</dependency>
生成鉴权令牌的代码如下
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.*;
import io.jsonwebtoken.lang.Maps;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Map;
public class JsonWebTokenFactory {
// 实际开发时请将公网地址存储在配置文件或数据库
private static final String AUD = "https://oauth-login.cloud.huawei.com/oauth2/v3/token";
public static String createJwt() throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, NullPointerException {
// 读取配置文件
ObjectMapper mapper = new ObjectMapper();
// 上述private.json文件放置于工程的src/main/resources路径下
URL url = JsonWebTokenFactory.class.getClassLoader().getResource("private.json");
if (url == null) {
throw new NullPointerException("File not exist");
}
JsonNode rootNode = mapper.readTree(new File(url.getPath()));
RSAPrivateKey privateKey = (RSAPrivateKey) generatePrivateKey(rootNode.get("private_key").asText()
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s", ""));
long iat = System.currentTimeMillis() / 1000;
long exp = iat + 3600;
Map<String, Object> header = Maps.<String, Object>of(JwsHeader.KEY_ID, rootNode.get("key_id").asText())
.and(JwsHeader.TYPE, JwsHeader.JWT_TYPE)
.and(JwsHeader.ALGORITHM, SignatureAlgorithm.PS256.getValue())
.build();
Map<String, Object> payload = Maps.<String, Object>of(Claims.ISSUER, rootNode.get("sub_account").asText())
.and(Claims.ISSUED_AT, iat)
.and(Claims.EXPIRATION, exp)
.and(Claims.AUDIENCE, AUD)
.build();
return Jwts.builder()
.setHeader(header)
.setPayload(new ObjectMapper().writeValueAsString(payload))
.signWith(privateKey, SignatureAlgorithm.PS256)
.compact();
}
private static PrivateKey generatePrivateKey(String base64Key) throws NoSuchAlgorithmException, InvalidKeySpecException {
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(base64Key.getBytes(StandardCharsets.UTF_8)));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(keySpec);
}
public static void main(String[] args) {
try {
// 获取鉴权令牌
String jwt = createJwt();
} catch (NoSuchAlgorithmException e) {
// 异常处理流程1
} catch (InvalidKeySpecException e) {
// 异常处理流程2
} catch (IOException e) {
// 异常处理流程3
} catch (NullPointerException e) {
// 异常处理流程4
}
}
}
需要注意⚠️的是要先下载推送服务API的服务账号密钥文件,具体的下载方法可以查看官方文档,链接为:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/push-jwt-token#section16173145352。
鉴权令牌生成后就可以进行消息的推送了,下面是我写的示例代码
/**
* 发送测试推送消息
*/
public boolean pushTestMessage(String token, String title, String body) {
return pushMessage(List.of(token), title, body, null, true);
}
/**
* 发送推送消息的核心方法
*
* @param tokens 设备token列表
* @param title 通知标题
* @param body 通知内容
* @param customData 自定义数据
* @param isTest 是否为测试消息
* @return 是否发送成功
*/
public boolean pushMessage(List<String> tokens, String title, String body, Map<String, String> customData, boolean isTest) {
try {
// String accessToken = getAccessToken();
String accessToken = JsonWebTokenFactory.createJwt();
return sendPushMessage(accessToken, tokens, title, body, customData, isTest);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 发送推送消息的核心实现
*/
private boolean sendPushMessage(String accessToken, List<String> tokens, String title, String body, Map<String, String> customData, boolean isTest) {
try {
// 构建请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, StandardCharsets.UTF_8));
headers.setBearerAuth(accessToken);
headers.set("push-type", "0"); // 华为推送要求的请求头
// 构建请求体
Map<String, Object> requestBody = buildRequestBody(tokens, title, body, customData, isTest);
HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, headers);
// 发送请求
String url = PUSH_URL.replace("{projectId}", projectId);
ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
if (response.getStatusCode() == HttpStatus.OK) {
System.out.println("推送成功: " + response.getBody());
return true;
} else {
System.err.println("推送失败: " + response.getBody());
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 构建华为推送请求体
*/
private Map<String, Object> buildRequestBody(List<String> tokens, String title, String body, Map<String, String> customData, boolean isTest) {
Map<String, Object> requestBody = new HashMap<>();
// 构建 payload
Map<String, Object> payload = new HashMap<>();
// 构建 notification
Map<String, Object> notification = new HashMap<>();
notification.put("category", "MARKETING");
notification.put("title", title);
notification.put("body", body);
notification.put("notifyId", 12345);
// 构建 clickAction
Map<String, Object> clickAction = new HashMap<>();
clickAction.put("actionType", 0);
notification.put("clickAction", clickAction);
// 设置前台是否显示通知,默认true表示前后台都展示
notification.put("foregroundShow", true);
payload.put("notification", notification);
// 如果有自定义数据,添加到payload中
if (customData != null && !customData.isEmpty()) {
payload.put("data", customData);
}
requestBody.put("payload", payload);
// 构建 target
Map<String, Object> target = new HashMap<>();
target.put("token", tokens);
requestBody.put("target", target);
// 构建 pushOptions
Map<String, Object> pushOptions = new HashMap<>();
pushOptions.put("testMessage", isTest);
// pushOptions.put("ttl", 86400); // 消息存活时间,默认24小时
requestBody.put("pushOptions", pushOptions);
return requestBody;
}
通过下面的方式调用就可以实现服务端推送消息到客户端了
pushTestMessage(user.getPushToken(), "记得记账哦!", "晚上好,今日是否还有收支未记录?");
这篇文章只是推送普通消息的指南,目标是让你跑通基本的业务,如果你的项目中有其他的一些特殊要求,可以查看官方文档。