M3(T-M2-04/T-M3-13): LocalUploadServer 截图上传分享链路落地
补「H5 主动 POST 截图上传分享」链路,对齐原工程 OkHttpPhotoServer + savehandler:
- LocalUploadServer 从骨架实现为真实本机 HTTP server(@ohos.net.socket TCPSocketServer):
127.0.0.1:8099 起逐端口重试 listen;手解极简 HTTP/1.1(\r\n\r\n 分隔 + Content-Length
累积读全 body);仅 POST /testurl,body 取 base64(form name=/raw 兼容)+type → emit
PHOTO_UPLOAD → 回 200;非 /testurl 回 404;16MB 上限;异常 log 不崩溃。
baseUrl 反映实际端口。注:TCPSocketServer 无显式 close,stop 用 off('connect')+释放引用
- common ShareEvents.PHOTO_UPLOAD + PhotoUploadPayload
- ShareProvider:订阅 PHOTO_UPLOAD(仅激活槽处理,避免双实例重复分享)→ 落盘 → 微信图片
分享(type=="1"好友/其他朋友圈)→ sharesuccess;onDestroy 退订;抽 wechatImageByFriend/
wechatSceneByFriend 供面板截图与 POST 上传两条链路共用
真机验证项:H5 真实 POST body 格式、127.0.0.1 端口可达、微信开放平台注册
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
cb3673cb1b
commit
187e73a549
@@ -24,7 +24,7 @@ import { BusinessError } from '@kit.BasicServicesKit';
|
||||
import { util } from '@kit.ArkTS';
|
||||
import { BridgeController } from 'feature_bridge';
|
||||
import { InboundHandlers, OutboundHandlers, SharetypeBean, ShareSuccessResp } from 'contracts';
|
||||
import { EventBus, Logger, ShareEvents, SharePanelRequest, SharePanelResult } from 'common';
|
||||
import { EventBus, Logger, ShareEvents, SharePanelRequest, SharePanelResult, PhotoUploadPayload } from 'common';
|
||||
import { FileSystem } from 'platform';
|
||||
import { CapabilityContext, CapabilityProvider } from '../core/CapabilityProvider';
|
||||
import { WeChatApi } from '../wx/WeChatApi';
|
||||
@@ -39,6 +39,8 @@ export class ShareProvider implements CapabilityProvider {
|
||||
private ctx: CapabilityContext | undefined = undefined;
|
||||
/** 截图落盘 + resultEvent 命名计数器(实例自增,避免 Math.random 串扰)。 */
|
||||
private seq: number = 0;
|
||||
/** PHOTO_UPLOAD 订阅退订函数(onDestroy 调用,防双槽实例泄漏/串扰)。 */
|
||||
private photoUploadCancel: (() => void) | undefined = undefined;
|
||||
|
||||
constructor() {
|
||||
ShareProvider.instanceCount += 1;
|
||||
@@ -51,6 +53,55 @@ export class ShareProvider implements CapabilityProvider {
|
||||
bridge.registerHandler(InboundHandlers.FriendsShare, (data: string, _cb: (resp: string) => void) => {
|
||||
this.onShare(data);
|
||||
});
|
||||
// 第二条链路:H5 主动 POST 截图到 LocalUploadServer → emit PHOTO_UPLOAD → 微信图片分享。
|
||||
this.photoUploadCancel = EventBus.on(ShareEvents.PHOTO_UPLOAD, (p) => this.onPhotoUpload(p));
|
||||
}
|
||||
|
||||
/** 容器销毁:退订 PHOTO_UPLOAD(双槽各一实例,须 per-subscriber 退订,勿 offAll)。 */
|
||||
onDestroy(): void {
|
||||
if (this.photoUploadCancel !== undefined) {
|
||||
this.photoUploadCancel();
|
||||
this.photoUploadCancel = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* H5 POST 截图上传分享:仅当本槽桥激活时处理(非激活槽忽略,避免双实例对同一上传重复分享)。
|
||||
* type 语义同 sharefriend:"1" 好友 → WXSceneSession/回传 type=1;其他 → 朋友圈/回传 type=2。
|
||||
* 落盘成功走微信图片分享;微信未装 reportResult(3, ...);落盘失败仅 log(无网页可降级)。
|
||||
*/
|
||||
private onPhotoUpload(payload?: Object): void {
|
||||
const ctx = this.ctx;
|
||||
const bridge = this.bridge;
|
||||
if (ctx === undefined || bridge === undefined) {
|
||||
return;
|
||||
}
|
||||
if (!bridge.isActive()) {
|
||||
return; // 非激活槽不处理,保证同一上传仅激活槽分享一次
|
||||
}
|
||||
if (payload === undefined) {
|
||||
return;
|
||||
}
|
||||
const up = payload as PhotoUploadPayload;
|
||||
if (up.imageBase64 === '') {
|
||||
this.log.w('photo upload empty image');
|
||||
return;
|
||||
}
|
||||
const friendType: number = up.type === '1' ? 1 : 2;
|
||||
const wx: WeChatApi = WeChatApi.getInstance();
|
||||
if (!wx.isWXInstalled()) {
|
||||
this.log.i('WeChat not installed (photo upload); report cancel');
|
||||
this.reportResult(3, friendType);
|
||||
return;
|
||||
}
|
||||
// saveDataUrlToFile 对无 data: 前缀的纯 base64 也兼容(indexOf(',')<0 → 整串当 base64)
|
||||
const filePath: string = this.saveDataUrlToFile(ctx.uiAbilityContext, up.imageBase64);
|
||||
if (filePath === '') {
|
||||
this.log.w('photo upload save failed');
|
||||
this.reportResult(3, friendType);
|
||||
return;
|
||||
}
|
||||
this.wechatImageByFriend(ctx.uiAbilityContext, wx, filePath, friendType);
|
||||
}
|
||||
|
||||
/** 入站:校验 bean → 发起面板请求(一对一回投)。 */
|
||||
@@ -134,7 +185,12 @@ export class ShareProvider implements CapabilityProvider {
|
||||
}
|
||||
|
||||
private wechatScene(bean: SharetypeBean): number {
|
||||
return bean.sharefriend === '1' ? SendMessageToWXReq.WXSceneSession : SendMessageToWXReq.WXSceneTimeline;
|
||||
return this.wechatSceneByFriend(bean.sharefriend === '1' ? 1 : 2);
|
||||
}
|
||||
|
||||
/** friendType: 1 好友(WXSceneSession) / 2 朋友圈(WXSceneTimeline)。 */
|
||||
private wechatSceneByFriend(friendType: number): number {
|
||||
return friendType === 1 ? SendMessageToWXReq.WXSceneSession : SendMessageToWXReq.WXSceneTimeline;
|
||||
}
|
||||
|
||||
private wechatWebPage(ctx: common.UIAbilityContext, wx: WeChatApi, bean: SharetypeBean, reportType: number): void {
|
||||
@@ -154,15 +210,21 @@ export class ShareProvider implements CapabilityProvider {
|
||||
|
||||
private wechatImage(ctx: common.UIAbilityContext, wx: WeChatApi, filePath: string,
|
||||
bean: SharetypeBean, reportType: number): void {
|
||||
this.wechatImageByFriend(ctx, wx, filePath, reportType);
|
||||
}
|
||||
|
||||
/** 微信图片分享(友/圈由 friendType 决定);分享面板与 H5 POST 上传两条链路共用。
|
||||
* friendType 同时作为 sharesuccess 回传的 type(1 好友 / 2 朋友圈)。 */
|
||||
private wechatImageByFriend(ctx: common.UIAbilityContext, wx: WeChatApi, filePath: string, friendType: number): void {
|
||||
const req: SendMessageToWXReq = new SendMessageToWXReq();
|
||||
req.scene = this.wechatScene(bean);
|
||||
req.scene = this.wechatSceneByFriend(friendType);
|
||||
const msg: WXMediaMessage = new WXMediaMessage();
|
||||
const img: WXImageObject = new WXImageObject();
|
||||
img.uri = fileUri.getUriFromPath(filePath); // 沙箱文件 file uri,SDK 支持 jpeg/png
|
||||
msg.mediaObject = img;
|
||||
req.message = msg;
|
||||
wx.sendShare(ctx, req, (resp) => {
|
||||
this.reportResult(resp.errCode === ErrCode.ERR_OK ? 2 : 3, reportType);
|
||||
this.reportResult(resp.errCode === ErrCode.ERR_OK ? 2 : 3, friendType);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user