feat: 校验 SDK 初始化时 packageName 与平台配置的 appKey 是否匹配
- im/push/update 三个服务登录/检查更新接口新增必填参数 packageName - 调用对应服务的 tenant-service 内部接口获取 platformInfo,与传入包名比对,不匹配返回 403 - update 服务按 platform 字段精确匹配(ANDROID/IOS/HARMONY 各用对应字段) - im/push 服务对三端包名任一匹配即通过 - ImAppSecretClient / PushAppSecretClient 新增 getPlatformInfo 缓存方法 - 新增 UpdateTenantClient 用于 update-service 调用 tenant-service platformInfo 接口 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
父节点
4c0db6e9b7
当前提交
0a267c5f70
@ -1,7 +1,9 @@
|
|||||||
package com.xuqm.im.controller;
|
package com.xuqm.im.controller;
|
||||||
|
|
||||||
|
import com.xuqm.common.exception.BusinessException;
|
||||||
import com.xuqm.common.model.ApiResponse;
|
import com.xuqm.common.model.ApiResponse;
|
||||||
import com.xuqm.im.service.ImAccountService;
|
import com.xuqm.im.service.ImAccountService;
|
||||||
|
import com.xuqm.im.service.ImAppSecretClient;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -16,20 +18,38 @@ import java.util.Map;
|
|||||||
public class AuthController {
|
public class AuthController {
|
||||||
|
|
||||||
private final ImAccountService accountService;
|
private final ImAccountService accountService;
|
||||||
|
private final ImAppSecretClient appSecretClient;
|
||||||
|
|
||||||
public AuthController(ImAccountService accountService) {
|
public AuthController(ImAccountService accountService, ImAppSecretClient appSecretClient) {
|
||||||
this.accountService = accountService;
|
this.accountService = accountService;
|
||||||
|
this.appSecretClient = appSecretClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public ResponseEntity<ApiResponse<Map<String, Object>>> login(
|
public ResponseEntity<ApiResponse<Map<String, Object>>> login(
|
||||||
@RequestParam @NotBlank String appKey,
|
@RequestParam @NotBlank String appKey,
|
||||||
@RequestParam @NotBlank String userId,
|
@RequestParam @NotBlank String userId,
|
||||||
@RequestParam @NotBlank String userSig) {
|
@RequestParam @NotBlank String userSig,
|
||||||
|
@RequestParam @NotBlank String packageName) {
|
||||||
if (userSig.isBlank()) {
|
if (userSig.isBlank()) {
|
||||||
return ResponseEntity.status(401).body(ApiResponse.error(401, "Missing userSig"));
|
return ResponseEntity.status(401).body(ApiResponse.error(401, "Missing userSig"));
|
||||||
}
|
}
|
||||||
|
validatePackageName(appKey, packageName);
|
||||||
ImAccountService.LoginResult result = accountService.loginWithUserSig(appKey, userId, userSig);
|
ImAccountService.LoginResult result = accountService.loginWithUserSig(appKey, userId, userSig);
|
||||||
return ResponseEntity.ok(ApiResponse.success(Map.of("token", result.token(), "admin", result.admin())));
|
return ResponseEntity.ok(ApiResponse.success(Map.of("token", result.token(), "admin", result.admin())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validatePackageName(String appKey, String packageName) {
|
||||||
|
ImAppSecretClient.PlatformInfo info = appSecretClient.getPlatformInfo(appKey);
|
||||||
|
String android = info.androidPackageName();
|
||||||
|
String ios = info.iosBundleId();
|
||||||
|
String harmony = info.harmonyBundleName();
|
||||||
|
boolean anyConfigured = hasText(android) || hasText(ios) || hasText(harmony);
|
||||||
|
if (anyConfigured) {
|
||||||
|
boolean matches = packageName.equals(android) || packageName.equals(ios) || packageName.equals(harmony);
|
||||||
|
if (!matches) throw new BusinessException(403, "包名与应用配置不匹配");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasText(String s) { return s != null && !s.isBlank(); }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,8 +18,11 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
@Component
|
@Component
|
||||||
public class ImAppSecretClient {
|
public class ImAppSecretClient {
|
||||||
|
|
||||||
|
public record PlatformInfo(String androidPackageName, String iosBundleId, String harmonyBundleName) {}
|
||||||
|
|
||||||
private final RestTemplate restTemplate = new RestTemplate();
|
private final RestTemplate restTemplate = new RestTemplate();
|
||||||
private final Map<String, String> cache = new ConcurrentHashMap<>();
|
private final Map<String, String> secretCache = new ConcurrentHashMap<>();
|
||||||
|
private final Map<String, PlatformInfo> platformInfoCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@Value("${im.tenant-service-url:http://127.0.0.1:8081}")
|
@Value("${im.tenant-service-url:http://127.0.0.1:8081}")
|
||||||
private String tenantServiceUrl;
|
private String tenantServiceUrl;
|
||||||
@ -28,7 +31,11 @@ public class ImAppSecretClient {
|
|||||||
private String internalToken;
|
private String internalToken;
|
||||||
|
|
||||||
public String getAppSecret(String appKey) {
|
public String getAppSecret(String appKey) {
|
||||||
return cache.computeIfAbsent(appKey, this::fetchAppSecret);
|
return secretCache.computeIfAbsent(appKey, this::fetchAppSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlatformInfo getPlatformInfo(String appKey) {
|
||||||
|
return platformInfoCache.computeIfAbsent(appKey, this::fetchPlatformInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String fetchAppSecret(String appKey) {
|
private String fetchAppSecret(String appKey) {
|
||||||
@ -56,4 +63,25 @@ public class ImAppSecretClient {
|
|||||||
}
|
}
|
||||||
throw new BusinessException(502, "Failed to resolve app secret for appKey: " + appKey);
|
throw new BusinessException(502, "Failed to resolve app secret for appKey: " + appKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PlatformInfo fetchPlatformInfo(String appKey) {
|
||||||
|
String url = UriComponentsBuilder.fromHttpUrl(tenantServiceUrl)
|
||||||
|
.path("/api/internal/sdk/apps/{appKey}/platform-info")
|
||||||
|
.buildAndExpand(appKey)
|
||||||
|
.toUriString();
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.set("X-Internal-Token", internalToken);
|
||||||
|
try {
|
||||||
|
ResponseEntity<JsonNode> response = restTemplate.exchange(
|
||||||
|
url, HttpMethod.GET, new HttpEntity<>(headers), JsonNode.class);
|
||||||
|
JsonNode data = response.getBody() == null ? null : response.getBody().path("data");
|
||||||
|
if (response.getStatusCode().is2xxSuccessful() && data != null && !data.isMissingNode()) {
|
||||||
|
return new PlatformInfo(
|
||||||
|
data.path("androidPackageName").asText(null),
|
||||||
|
data.path("iosBundleId").asText(null),
|
||||||
|
data.path("harmonyBundleName").asText(null));
|
||||||
|
}
|
||||||
|
} catch (RestClientException ignored) {}
|
||||||
|
return new PlatformInfo(null, null, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
package com.xuqm.push.controller;
|
package com.xuqm.push.controller;
|
||||||
|
|
||||||
|
import com.xuqm.common.exception.BusinessException;
|
||||||
import com.xuqm.common.model.ApiResponse;
|
import com.xuqm.common.model.ApiResponse;
|
||||||
import com.xuqm.push.entity.DeviceTokenEntity;
|
import com.xuqm.push.entity.DeviceTokenEntity;
|
||||||
import com.xuqm.push.service.PushAccountService;
|
import com.xuqm.push.service.PushAccountService;
|
||||||
|
import com.xuqm.push.service.PushAppSecretClient;
|
||||||
import com.xuqm.push.service.PushDispatcher;
|
import com.xuqm.push.service.PushDispatcher;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -18,21 +20,21 @@ public class PushAuthController {
|
|||||||
|
|
||||||
private final PushAccountService accountService;
|
private final PushAccountService accountService;
|
||||||
private final PushDispatcher pushDispatcher;
|
private final PushDispatcher pushDispatcher;
|
||||||
|
private final PushAppSecretClient appSecretClient;
|
||||||
|
|
||||||
public PushAuthController(PushAccountService accountService, PushDispatcher pushDispatcher) {
|
public PushAuthController(PushAccountService accountService, PushDispatcher pushDispatcher,
|
||||||
|
PushAppSecretClient appSecretClient) {
|
||||||
this.accountService = accountService;
|
this.accountService = accountService;
|
||||||
this.pushDispatcher = pushDispatcher;
|
this.pushDispatcher = pushDispatcher;
|
||||||
|
this.appSecretClient = appSecretClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Login with userSig. On success, automatically registers the device push token.
|
|
||||||
* Returns a pushToken (JWT) used to authenticate subsequent push service requests.
|
|
||||||
*/
|
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public ResponseEntity<ApiResponse<Map<String, Object>>> login(
|
public ResponseEntity<ApiResponse<Map<String, Object>>> login(
|
||||||
@RequestParam String appKey,
|
@RequestParam String appKey,
|
||||||
@RequestParam String userId,
|
@RequestParam String userId,
|
||||||
@RequestParam String userSig,
|
@RequestParam String userSig,
|
||||||
|
@RequestParam String packageName,
|
||||||
@RequestParam DeviceTokenEntity.Vendor vendor,
|
@RequestParam DeviceTokenEntity.Vendor vendor,
|
||||||
@RequestParam String token,
|
@RequestParam String token,
|
||||||
@RequestParam(required = false) String platform,
|
@RequestParam(required = false) String platform,
|
||||||
@ -42,6 +44,7 @@ public class PushAuthController {
|
|||||||
@RequestParam(required = false) String osVersion,
|
@RequestParam(required = false) String osVersion,
|
||||||
@RequestParam(required = false) String appVersion) {
|
@RequestParam(required = false) String appVersion) {
|
||||||
|
|
||||||
|
validatePackageName(appKey, packageName);
|
||||||
PushAccountService.LoginResult result = accountService.loginWithUserSig(appKey, userId, userSig);
|
PushAccountService.LoginResult result = accountService.loginWithUserSig(appKey, userId, userSig);
|
||||||
pushDispatcher.registerToken(appKey, userId, vendor, token, platform, deviceId, brand, model, osVersion, appVersion);
|
pushDispatcher.registerToken(appKey, userId, vendor, token, platform, deviceId, brand, model, osVersion, appVersion);
|
||||||
|
|
||||||
@ -53,4 +56,21 @@ public class PushAuthController {
|
|||||||
);
|
);
|
||||||
return ResponseEntity.ok(ApiResponse.success(response));
|
return ResponseEntity.ok(ApiResponse.success(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validatePackageName(String appKey, String packageName) {
|
||||||
|
if (packageName == null || packageName.isBlank()) {
|
||||||
|
throw new BusinessException(403, "packageName is required");
|
||||||
|
}
|
||||||
|
PushAppSecretClient.PlatformInfo info = appSecretClient.getPlatformInfo(appKey);
|
||||||
|
String android = info.androidPackageName();
|
||||||
|
String ios = info.iosBundleId();
|
||||||
|
String harmony = info.harmonyBundleName();
|
||||||
|
boolean anyConfigured = hasText(android) || hasText(ios) || hasText(harmony);
|
||||||
|
if (anyConfigured) {
|
||||||
|
boolean matches = packageName.equals(android) || packageName.equals(ios) || packageName.equals(harmony);
|
||||||
|
if (!matches) throw new BusinessException(403, "包名与应用配置不匹配");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasText(String s) { return s != null && !s.isBlank(); }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,8 +18,11 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
@Component
|
@Component
|
||||||
public class PushAppSecretClient {
|
public class PushAppSecretClient {
|
||||||
|
|
||||||
|
public record PlatformInfo(String androidPackageName, String iosBundleId, String harmonyBundleName) {}
|
||||||
|
|
||||||
private final RestTemplate restTemplate = new RestTemplate();
|
private final RestTemplate restTemplate = new RestTemplate();
|
||||||
private final Map<String, String> cache = new ConcurrentHashMap<>();
|
private final Map<String, String> secretCache = new ConcurrentHashMap<>();
|
||||||
|
private final Map<String, PlatformInfo> platformInfoCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@Value("${push.tenant-service-url:http://127.0.0.1:8081}")
|
@Value("${push.tenant-service-url:http://127.0.0.1:8081}")
|
||||||
private String tenantServiceUrl;
|
private String tenantServiceUrl;
|
||||||
@ -28,7 +31,11 @@ public class PushAppSecretClient {
|
|||||||
private String internalToken;
|
private String internalToken;
|
||||||
|
|
||||||
public String getAppSecret(String appKey) {
|
public String getAppSecret(String appKey) {
|
||||||
return cache.computeIfAbsent(appKey, this::fetchAppSecret);
|
return secretCache.computeIfAbsent(appKey, this::fetchAppSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlatformInfo getPlatformInfo(String appKey) {
|
||||||
|
return platformInfoCache.computeIfAbsent(appKey, this::fetchPlatformInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String fetchAppSecret(String appKey) {
|
private String fetchAppSecret(String appKey) {
|
||||||
@ -56,4 +63,25 @@ public class PushAppSecretClient {
|
|||||||
}
|
}
|
||||||
throw new BusinessException(502, "Failed to resolve app secret for appKey: " + appKey);
|
throw new BusinessException(502, "Failed to resolve app secret for appKey: " + appKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PlatformInfo fetchPlatformInfo(String appKey) {
|
||||||
|
String url = UriComponentsBuilder.fromHttpUrl(tenantServiceUrl)
|
||||||
|
.path("/api/internal/sdk/apps/{appKey}/platform-info")
|
||||||
|
.buildAndExpand(appKey)
|
||||||
|
.toUriString();
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.set("X-Internal-Token", internalToken);
|
||||||
|
try {
|
||||||
|
ResponseEntity<JsonNode> response = restTemplate.exchange(
|
||||||
|
url, HttpMethod.GET, new HttpEntity<>(headers), JsonNode.class);
|
||||||
|
JsonNode data = response.getBody() == null ? null : response.getBody().path("data");
|
||||||
|
if (response.getStatusCode().is2xxSuccessful() && data != null && !data.isMissingNode()) {
|
||||||
|
return new PlatformInfo(
|
||||||
|
data.path("androidPackageName").asText(null),
|
||||||
|
data.path("iosBundleId").asText(null),
|
||||||
|
data.path("harmonyBundleName").asText(null));
|
||||||
|
}
|
||||||
|
} catch (RestClientException ignored) {}
|
||||||
|
return new PlatformInfo(null, null, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,8 @@ import com.xuqm.update.service.UpdateAssetService;
|
|||||||
import com.xuqm.update.service.PublishConfigService;
|
import com.xuqm.update.service.PublishConfigService;
|
||||||
import com.xuqm.update.service.AppStoreService;
|
import com.xuqm.update.service.AppStoreService;
|
||||||
import com.xuqm.update.service.ImPushUserClient;
|
import com.xuqm.update.service.ImPushUserClient;
|
||||||
|
import com.xuqm.update.service.UpdateTenantClient;
|
||||||
|
import com.xuqm.common.exception.BusinessException;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/updates")
|
@RequestMapping("/api/v1/updates")
|
||||||
@ -33,21 +35,23 @@ public class AppVersionController {
|
|||||||
private final PublishConfigService publishConfigService;
|
private final PublishConfigService publishConfigService;
|
||||||
private final AppStoreService appStoreService;
|
private final AppStoreService appStoreService;
|
||||||
private final UpdateOperationLogService operationLogService;
|
private final UpdateOperationLogService operationLogService;
|
||||||
|
|
||||||
private final ImPushUserClient imPushUserClient;
|
private final ImPushUserClient imPushUserClient;
|
||||||
|
private final UpdateTenantClient tenantClient;
|
||||||
|
|
||||||
public AppVersionController(AppVersionRepository versionRepository,
|
public AppVersionController(AppVersionRepository versionRepository,
|
||||||
UpdateAssetService updateAssetService,
|
UpdateAssetService updateAssetService,
|
||||||
PublishConfigService publishConfigService,
|
PublishConfigService publishConfigService,
|
||||||
AppStoreService appStoreService,
|
AppStoreService appStoreService,
|
||||||
UpdateOperationLogService operationLogService,
|
UpdateOperationLogService operationLogService,
|
||||||
ImPushUserClient imPushUserClient) {
|
ImPushUserClient imPushUserClient,
|
||||||
|
UpdateTenantClient tenantClient) {
|
||||||
this.versionRepository = versionRepository;
|
this.versionRepository = versionRepository;
|
||||||
this.updateAssetService = updateAssetService;
|
this.updateAssetService = updateAssetService;
|
||||||
this.publishConfigService = publishConfigService;
|
this.publishConfigService = publishConfigService;
|
||||||
this.appStoreService = appStoreService;
|
this.appStoreService = appStoreService;
|
||||||
this.operationLogService = operationLogService;
|
this.operationLogService = operationLogService;
|
||||||
this.imPushUserClient = imPushUserClient;
|
this.imPushUserClient = imPushUserClient;
|
||||||
|
this.tenantClient = tenantClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/app/check")
|
@GetMapping("/app/check")
|
||||||
@ -55,8 +59,10 @@ public class AppVersionController {
|
|||||||
@RequestParam String appKey,
|
@RequestParam String appKey,
|
||||||
@RequestParam AppVersionEntity.Platform platform,
|
@RequestParam AppVersionEntity.Platform platform,
|
||||||
@RequestParam int currentVersionCode,
|
@RequestParam int currentVersionCode,
|
||||||
|
@RequestParam @jakarta.validation.constraints.NotBlank String packageName,
|
||||||
@RequestParam(required = false) String userId) {
|
@RequestParam(required = false) String userId) {
|
||||||
|
|
||||||
|
validatePackageName(appKey, platform, packageName);
|
||||||
boolean allowAnonymousCheck = publishConfigService.allowAnonymousUpdateCheck(appKey);
|
boolean allowAnonymousCheck = publishConfigService.allowAnonymousUpdateCheck(appKey);
|
||||||
|
|
||||||
Optional<AppVersionEntity> latest = versionRepository
|
Optional<AppVersionEntity> latest = versionRepository
|
||||||
@ -489,6 +495,18 @@ public class AppVersionController {
|
|||||||
return currentStatus == AppVersionEntity.PublishStatus.PUBLISHED ? "PUBLISH" : "SAVE_DRAFT";
|
return currentStatus == AppVersionEntity.PublishStatus.PUBLISHED ? "PUBLISH" : "SAVE_DRAFT";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validatePackageName(String appKey, AppVersionEntity.Platform platform, String packageName) {
|
||||||
|
UpdateTenantClient.PlatformInfo info = tenantClient.getPlatformInfo(appKey);
|
||||||
|
String registered = switch (platform) {
|
||||||
|
case IOS -> info.iosBundleId();
|
||||||
|
case HARMONY -> info.harmonyBundleName();
|
||||||
|
default -> info.androidPackageName();
|
||||||
|
};
|
||||||
|
if (hasText(registered) && !registered.equals(packageName)) {
|
||||||
|
throw new BusinessException(403, "包名与应用配置不匹配");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean hasText(String value) {
|
private boolean hasText(String value) {
|
||||||
return value != null && !value.isBlank();
|
return value != null && !value.isBlank();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,55 @@
|
|||||||
|
package com.xuqm.update.service;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.client.RestClientException;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class UpdateTenantClient {
|
||||||
|
|
||||||
|
public record PlatformInfo(String androidPackageName, String iosBundleId, String harmonyBundleName) {}
|
||||||
|
|
||||||
|
private final RestTemplate restTemplate = new RestTemplate();
|
||||||
|
private final Map<String, PlatformInfo> cache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Value("${sdk.tenant-service-url:http://xuqm-tenant-service:9001}")
|
||||||
|
private String tenantServiceUrl;
|
||||||
|
|
||||||
|
@Value("${sdk.internal-token:xuqm-internal-token}")
|
||||||
|
private String internalToken;
|
||||||
|
|
||||||
|
public PlatformInfo getPlatformInfo(String appKey) {
|
||||||
|
return cache.computeIfAbsent(appKey, this::fetchPlatformInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlatformInfo fetchPlatformInfo(String appKey) {
|
||||||
|
String url = UriComponentsBuilder.fromHttpUrl(tenantServiceUrl)
|
||||||
|
.path("/api/internal/sdk/apps/{appKey}/platform-info")
|
||||||
|
.buildAndExpand(appKey)
|
||||||
|
.toUriString();
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.set("X-Internal-Token", internalToken);
|
||||||
|
try {
|
||||||
|
ResponseEntity<JsonNode> response = restTemplate.exchange(
|
||||||
|
url, HttpMethod.GET, new HttpEntity<>(headers), JsonNode.class);
|
||||||
|
JsonNode data = response.getBody() == null ? null : response.getBody().path("data");
|
||||||
|
if (response.getStatusCode().is2xxSuccessful() && data != null && !data.isMissingNode()) {
|
||||||
|
return new PlatformInfo(
|
||||||
|
data.path("androidPackageName").asText(null),
|
||||||
|
data.path("iosBundleId").asText(null),
|
||||||
|
data.path("harmonyBundleName").asText(null));
|
||||||
|
}
|
||||||
|
} catch (RestClientException ignored) {}
|
||||||
|
return new PlatformInfo(null, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
正在加载...
在新工单中引用
屏蔽一个用户