1
0

2 Коммиты be77051ba3 ... c02b763fb0

Автор SHA1 Сообщение Дата
  chenritian c02b763fb0 微信登录获取用户信息 2 недель назад
  chenritian 264b27170d 微信登录获取授权码回调 2 недель назад

+ 15 - 2
entry/src/main/ets/apis/WechatApi.ets

@@ -1,10 +1,10 @@
-import { AccessTokenResponse } from '../model/WechatModel';
+import { AccessTokenResponse, WeChatUserInfo } from '../model/WechatModel';
 import { WechatUtil } from '../utils/wechat/WechatUtil';
 import { YTRequest } from './YTRequest';
 
 export class WechatApi {
   /**
-   * 获取code
+   * 获取AccessToken
    */
   static async getAccessToken(code: string, appSecret: string) {
     const url =
@@ -16,4 +16,17 @@ export class WechatApi {
       grant_type: 'authorization_code'
     })
   }
+
+  /**
+   * 获取个人信息
+   */
+  static async getUserInfo(accessToken: string, openId: string) {
+    const url =
+      `https://api.weixin.qq.com/sns/userinfo`;
+    return await YTRequest.get<WeChatUserInfo>(url, {
+      access_token: accessToken,
+      openid: openId,
+      lang: 'zh_CN'
+    })
+  }
 }

+ 1 - 1
entry/src/main/ets/entryability/EntryAbility.ets

@@ -16,7 +16,7 @@ export default class EntryAbility extends UIAbility {
   onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
     try {
       this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
-      WechatUtil.init()
+      this.handleWeChatCallIfNeed(want)
     } catch (err) {
       hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err));
     }

+ 78 - 44
entry/src/main/ets/model/JDBModel.ets

@@ -1,13 +1,53 @@
-import { Pay } from '@cashier_alipay/cashiersdk';
-import { IBestToast } from '@ibestservices/ibest-ui';
-import { PayReq, SendAuthReq } from '@tencent/wechat_open_sdk';
-import { ContextHelper } from '../utils/ContextHelper';
 import { WechatUtil } from '../utils/wechat/WechatUtil';
-import { jDBViewModel } from '../viewModels/JDBViewModel';
 import { WeChatPayParams } from './WechatModel';
-import { BusinessError } from '@kit.BasicServicesKit';
 import { ALiPayUtil } from '../utils/alipay/ALiPayUtil';
 
+
+/**
+ * 分享参数
+ */
+/**
+ * 微信分享参数接口
+ */
+export interface ShareParams {
+  /**
+   * 提供商标识
+   */
+  provider?: string;
+
+  /**
+   * 分享场景
+   * WXSceneSession-会话 WXSceneTimeline-朋友圈
+   */
+  scene?: 'WXSceneSession' | 'WXSceneTimeline';
+
+  /**
+   * 分享类型 0图文 1文字 2图片
+   */
+  type?: number;
+
+  /**
+   * 分享链接
+   */
+  href?: string;
+
+  /**
+   * 分享标题
+   */
+  title?: string;
+
+  /**
+   * 分享摘要
+   */
+  summary?: string;
+
+  /**
+   * 分享图片URL
+   */
+  imageUrl?: string;
+}
+
+
 export interface RunH5Param {
   // type: 'wx_login'-微信登录 | 'wx_pay'-微信支付 | 'ali_login' 支付宝登录授权 | 'ali_pay' 支付宝支付
   // 'wx_share' - 微信分享 | 'wx_pyq_share' -微信朋友圈分享 | 'qq_share'QQ分享 | 'wx_code' - 微信授权码获取
@@ -17,55 +57,49 @@ export interface RunH5Param {
 
 
 export class JDBObj {
+  /**
+   * 微信登录
+   * @returns
+   */
   async handleWeChatLogin(): Promise<void> {
-    try {
-      let req = new SendAuthReq();
-      req.isOption1 = false;
-      req.nonAutomatic = true;
-      req.scope = 'snsapi_userinfo'; //应用授权作用域,获取用户个人信息则填写 snsapi_userinfo (只能填 snsapi_userinfo)
-      req.state = 'none';
-      req.transaction = 'test123';
-      let finished = await WechatUtil.getWechatApi().sendReq(ContextHelper.UIAbilityContext, req);
-    } catch (error) {
-      IBestToast.show({ message: '微信登录失败,请重试', type: 'fail' });
-    }
+    WechatUtil.handleWeChatLogin()
   }
 
+  /**
+   * 微信支付
+   * @returns
+   */
   async handleWeChatPay(param: WeChatPayParams) {
-    let req = new PayReq()
-    req.appId = param.appid
-    req.partnerId = param.partnerid
-    req.prepayId = param.prepayid
-    req.packageValue = param.package
-    req.nonceStr = param.noncestr
-    req.timeStamp = param.timestamp.toString()
-    req.sign = param.sign
-    await WechatUtil.getWechatApi().sendReq(ContextHelper.UIAbilityContext, req)
+    WechatUtil.handleWeChatPay(param)
   }
 
 
+  /**
+   * 支付宝登录
+   */
   handleAlipayAuthorization() {
     ALiPayUtil.startAuthorization()
   }
 
-
+  /**
+   * 支付宝支付
+   * @param orderInfo
+   */
   handleAliPay(orderInfo: string) {
-    IBestToast.show({ message: '开始支付:请求参数:' + orderInfo })
-    new Pay().pay(orderInfo, false).then((result) => {
-      let message =
-        `resultStatus: ${result.get('resultStatus')} memo: ${result.get('memo')} result: ${result.get('result')}`;
-      console.log(message);
-      jDBViewModel.runJavaScript({
-        type: 'ali_pay',
-        data: result.get('resultStatus')
-      })
-      IBestToast.show({ message: message })
-    }).catch((error: BusinessError) => {
-      console.log(error.message);
-      IBestToast.show({
-        message: error.message,
-        duration: 2000,
-      })
-    });
+    ALiPayUtil.handleAliPay(orderInfo)
+  }
+
+  /**
+   * 分享功能
+   */
+  async handleShare(shareParams: ShareParams) {
+    WechatUtil.handleWeChatShare(shareParams)
+  }
+
+  /**
+   * 分享功能
+   */
+  async handleWeChatShareTest(shareParams: ShareParams) {
+    WechatUtil.handleWeChatShareTest(shareParams)
   }
 }

+ 51 - 0
entry/src/main/ets/model/WechatModel.ets

@@ -69,4 +69,55 @@ export interface WeChatPayParams {
   sign: string;
 }
 
+/**
+ * 微信用户信息接口
+ */
+export interface WeChatUserInfo {
+  /**
+   * 普通用户的标识,对当前开发者账号唯一
+   */
+  openid: string;
+
+  /**
+   * 普通用户昵称
+   */
+  nickname: string;
+
+  /**
+   * 普通用户性别,1 为男性,2 为女性
+   */
+  sex: number;
+
+  /**
+   * 普通用户个人资料填写的省份
+   */
+  province: string;
+
+  /**
+   * 普通用户个人资料填写的城市
+   */
+  city: string;
+
+  /**
+   * 国家,如中国为 CN
+   */
+  country: string;
+
+  /**
+   * 用户头像,最后一个数值代表正方形头像大小(有 0、46、64、96、132 数值可选,0 代表 640*640 正方形头像),用户没有头像时该项为空
+   */
+  headimgurl: string;
+
+  /**
+   * 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom)
+   */
+  privilege: string[];
+
+  /**
+   * 用户统一标识。针对一个微信开放平台账号下的应用,同一用户的 unionid 是唯一的。
+   */
+  unionid?: string;
+}
+
+
 

+ 25 - 1
entry/src/main/ets/pages/Index.ets

@@ -158,6 +158,7 @@ struct Index {
             bottom: YTAvoid.getBottom()
           })
 
+          //TODO 测试数据
           Row() {
             Button('微信登录')
               .width(100)
@@ -173,10 +174,33 @@ struct Index {
               .onClick(() => {
                 jDBViewModel.jDBItem.handleAlipayAuthorization()
 
+              })
+            Button('分享')
+              .width(100)
+              .height(50)
+              .onClick(() => {
+                jDBViewModel.jDBItem.handleShare({
+                  imageUrl: 'https://file.ytmdm.com/jdb_logo.png',
+                  href: 'https://test.zcb.ytpm.net/website/',
+                  scene: 'WXSceneSession'
+                })
+
+              })
+
+            Button('分享测试')
+              .width(100)
+              .height(50)
+              .onClick(() => {
+                jDBViewModel.jDBItem.handleWeChatShareTest({
+                  imageUrl: 'https://file.ytmdm.com/jdb_logo.png',
+                  href: 'https://www.baidu.com',
+                  scene: 'WXSceneSession'
+                })
+
               })
           }
           .position({
-            left: '50%',
+            left: 0,
             bottom: 200
           })
 

+ 112 - 0
entry/src/main/ets/utils/ImageUtil.ets

@@ -0,0 +1,112 @@
+import { http } from '@kit.NetworkKit';
+import { image } from '@kit.ImageKit';
+import { IBestToast } from '@ibestservices/ibest-ui';
+import { BusinessError } from '@kit.BasicServicesKit';
+import { Context } from '@ohos.abilityAccessCtrl';
+import { util } from '@kit.ArkTS';
+import { fileIo as fs } from '@kit.CoreFileKit';
+import { ContextHelper } from './ContextHelper';
+
+
+export class ImageUtil {
+  // 根据url下载图片,获取的是ArrayBuffer对象
+
+  static async downLoadPic(url: string): Promise<ArrayBuffer | null> {
+
+    let data = await http.createHttp().request(url);
+
+    if (data.result instanceof ArrayBuffer) {
+
+      let imageData: ArrayBuffer = data.result
+
+      return imageData;
+
+    }
+    return null;
+
+  }
+
+  static async arrayBufToPixelMap(buf: ArrayBuffer): Promise<PixelMap> {
+
+    let imgSource: image.ImageSource = image.createImageSource(buf);
+
+    let result: PixelMap = await imgSource.createPixelMap();
+
+    return result;
+
+  }
+
+  /**
+   * 获取图片url
+   */
+  static async saveImageToBox(pixmap: PixelMap, context: Context) {
+
+    // 处理PixelMap数据
+    // 2. PixelMap数据 => 二进制
+    const packer = image.createImagePacker() // 创建一个图片打包转换器
+    // 图片打包转换器  接收PixelMap数据 传入打包配置(jpeg格式  质量100)
+    const arrayBuffer = await packer.packToData(pixmap, { format: 'image/jpeg', quality: 100 }) // 转换为二进制
+
+    // 3.创建图片一个文件  写入数据(二进制)
+    const imagePath = context.cacheDir + '/' + util.generateRandomUUID() + '.jpeg'
+    const file = fs.openSync(imagePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE)
+    fs.writeSync(file.fd, arrayBuffer)
+    return imagePath
+  }
+
+
+  /**
+   * 获取图片尺寸
+   */
+  static async getImageSize(context: UIContext, path: string, callback: (width: number, height: number) => void) {
+    const imageSource = image.createImageSource(path);
+    imageSource.getImageInfo((error: BusinessError, imageInfo: image.ImageInfo) => {
+      if (error) {
+        IBestToast.show('获取图片信息失败')
+      } else {
+        callback(context.px2vp(imageInfo.size.width), context.px2vp(imageInfo.size.height))
+      }
+    });
+  }
+
+  /**
+   * 手动压缩图片
+   */
+  static async manualCompression(filePath: string, quality: number, context: Context) {
+    const imageSourceApi: image.ImageSource = image.createImageSource(filePath);
+    let packOpts: image.PackingOption = { format: "image/jpeg", quality: quality };
+    const imagePackerApi = image.createImagePacker()
+    const buffer = await imagePackerApi.packing(imageSourceApi, packOpts)
+    const imagePath = context.cacheDir + '/' + util.generateRandomUUID() + '.jpeg'
+    const file = fs.openSync(imagePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE)
+    fs.writeSync(file.fd, buffer)
+    fs.closeSync(file)
+    fs.unlinkSync(filePath)
+    return imagePath
+  }
+
+
+  static async downLoadToBox(url: string) {
+    const buff = await ImageUtil.downLoadPic(url)
+    if (buff) {
+      const pixelMap = await ImageUtil.arrayBufToPixelMap(buff)
+      const original = await ImageUtil.saveImageToBox(pixelMap, ContextHelper.context)
+      //压缩图片
+      const localUrl = await ImageUtil.manualCompression(original, 10, ContextHelper.context)
+      return localUrl
+    }
+    return null
+  }
+
+  static async downLoadToBoxWithQuality(url: string, quality: number) {
+    const buff = await ImageUtil.downLoadPic(url)
+    if (buff) {
+      const imageSourceApi: image.ImageSource = image.createImageSource(buff);
+      let packOpts: image.PackingOption = { format: "image/jpeg", quality: quality };
+      const imagePackerApi = image.createImagePacker()
+      const buffer = await imagePackerApi.packing(imageSourceApi, packOpts)
+      return buffer
+    }
+    return null
+  }
+}

+ 33 - 1
entry/src/main/ets/utils/alipay/ALiPayUtil.ets

@@ -1,7 +1,10 @@
 import { AFAuthServiceResponse, AFService, AFServiceCenter, AFServiceParams, AFWantParams } from '@alipay/afservicesdk';
+import { Pay } from '@cashier_alipay/cashiersdk';
 import Want from '@ohos.app.ability.Want';
 import BuildProfile from 'BuildProfile';
 import { jDBViewModel } from '../../viewModels/JDBViewModel';
+import { BusinessError } from '@kit.BasicServicesKit';
+import { IBestToast } from '@ibestservices/ibest-ui';
 
 export class ALiPayUtil {
   static ALIPAY_APP_ID = '2021006101646784'
@@ -13,6 +16,9 @@ export class ALiPayUtil {
     return AFServiceCenter.handleResponse(want);
   }
 
+  /**
+   * 支付宝授权登录
+   */
   static startAuthorization() {
     /**
      * 构建参数
@@ -44,4 +50,30 @@ export class ALiPayUtil {
      */
     AFServiceCenter.call(AFService.AFServiceAuth, params)
   }
-}
+
+  /**
+   * 支付宝支付
+   */
+  /**
+   * 支付宝支付
+   * @param orderInfo:后端生成的订单信息
+   */
+  static handleAliPay(orderInfo: string) {
+    new Pay().pay(orderInfo, false).then((result) => {
+      let message =
+        `resultStatus: ${result.get('resultStatus')} memo: ${result.get('memo')} result: ${result.get('result')}`;
+      console.log(message);
+      jDBViewModel.runJavaScript({
+        type: 'ali_pay',
+        data: result.get('resultStatus')
+      })
+      // IBestToast.show({ message: message })
+    }).catch((error: BusinessError) => {
+      console.log(error.message);
+      IBestToast.show({
+        message: error.message,
+        duration: 2000,
+      })
+    });
+  }
+}

+ 13 - 4
entry/src/main/ets/utils/wechat/WXApiEventHandlerImpl.ets

@@ -59,10 +59,6 @@ export class WXApiEventHandlerImpl implements WXApiEventHandler {
     if (resp instanceof SendAuthResp) {
       if (resp.errCode === 0 && resp.code) {
         YTLog.info(TAG, `WeChat login success, code: ${resp.code}`);
-        jDBViewModel.runJavaScript({
-          type: 'wx_login',
-          data: resp
-        })
         this.handleLoginSuccess(resp.code);
       } else {
         YTLog.error(TAG, `WeChat login failed, errCode: ${resp.errCode}, errStr: ${resp.errStr}`);
@@ -96,7 +92,20 @@ export class WXApiEventHandlerImpl implements WXApiEventHandler {
         IBestToast.show({ type: 'fail', message: '获取微信授权码失败' })
         return;
       }
+
       //TODO 写微信调用后端接口逻辑
+      const userInfo = await WechatApi.getUserInfo(response.access_token, response.openid)
+      jDBViewModel.runJavaScript({
+        type: 'wx_login',
+        data: {
+          openId: userInfo.openid,
+          wechatIcon: userInfo.headimgurl,
+          wechatName: userInfo.nickname,
+          userId: userInfo.unionid,
+          code: code,
+          accessToken: response.access_token,
+        }
+      })
 
     } catch (error) {
       IBestToast.show({ type: 'fail', message: '获取微信授权码失败' })

+ 101 - 4
entry/src/main/ets/utils/wechat/WechatUtil.ets

@@ -1,6 +1,19 @@
-import { SendAuthReq, WXApi, WXAPIFactory } from '@tencent/wechat_open_sdk';
+import {
+  PayReq,
+  SendAuthReq,
+  SendMessageToWXReq,
+  WXApi,
+  WXAPIFactory,
+  WXImageObject,
+  WXMediaMessage,
+  WXWebpageObject
+} from '@tencent/wechat_open_sdk';
 import { ContextHelper } from '../ContextHelper';
 import { IBestToast } from '@ibestservices/ibest-ui';
+import { WeChatPayParams } from '../../model/WechatModel';
+import { ShareParams } from '../../model/JDBModel';
+import { ImageUtil } from '../ImageUtil';
+import { fileUri } from '@kit.CoreFileKit';
 
 export class WechatUtil {
   TAG: string = 'WeChatLoginUtils';
@@ -9,14 +22,98 @@ export class WechatUtil {
   static appSecret = '9207b18860aef2e784d14b413bf1ff79'
   static wechatApi: WXApi;
 
-  static init() {
+  static getWechatApi(): WXApi {
     if (!WechatUtil.wechatApi) {
       WechatUtil.wechatApi = WXAPIFactory.createWXAPI(WechatUtil.WECHAT_APP_ID_VALUE);
     }
+    return WechatUtil.wechatApi;
   }
 
-  static getWechatApi(): WXApi {
-    return WechatUtil.wechatApi;
+
+  /**
+   * 微信登录
+   * @returns
+   */
+  static async handleWeChatLogin(): Promise<void> {
+    try {
+      let req = new SendAuthReq();
+      req.isOption1 = false;
+      req.nonAutomatic = true;
+      req.scope = 'snsapi_userinfo'; //应用授权作用域,获取用户个人信息则填写 snsapi_userinfo (只能填 snsapi_userinfo)
+      req.state = 'none';
+      req.transaction = 'test123';
+      let finished = await WechatUtil.getWechatApi().sendReq(ContextHelper.UIAbilityContext, req);
+    } catch (error) {
+      IBestToast.show({ message: '微信登录失败,请重试', type: 'fail' });
+    }
+  }
+
+  /**
+   * 微信支付
+   * @returns
+   */
+  static async handleWeChatPay(param: WeChatPayParams) {
+    let req = new PayReq()
+    req.appId = param.appid
+    req.partnerId = param.partnerid
+    req.prepayId = param.prepayid
+    req.packageValue = param.package
+    req.nonceStr = param.noncestr
+    req.timeStamp = param.timestamp.toString()
+    req.sign = param.sign
+    await WechatUtil.getWechatApi().sendReq(ContextHelper.UIAbilityContext, req)
+  }
+
+  /**
+   * 微信分享
+   */
+  /**
+   * 微信分享
+   */
+  static async handleWeChatShare(shareData: ShareParams) {
+    // 下载并获取图片URI
+    const thumbBuffer = await ImageUtil.downLoadToBoxWithQuality(shareData.imageUrl!, 30)
+
+    // 创建网页对象,包含跳转链接
+    const webpageObject = new WXWebpageObject()
+    webpageObject.webpageUrl = shareData.href // 设置跳转链接
+
+    let mediaMessage = new WXMediaMessage()
+    mediaMessage.title = shareData.title || '「接单宝」✔ 任务简单 ✔ 上线就能赚✔ 提现快速到账'
+    mediaMessage.description = shareData.summary || '「接单宝」✔ 任务简单 ✔ 上线就能赚✔ 提现快速到账'
+    mediaMessage.thumbData = new Uint8Array(thumbBuffer!)
+    // mediaMessage.thumbMediaObject = imageObject // 设置缩略图
+    mediaMessage.mediaObject = webpageObject // 设置网页对象
+
+    let req = new SendMessageToWXReq()
+    req.scene = shareData.scene == 'WXSceneSession' ? SendMessageToWXReq.WXSceneSession :
+      SendMessageToWXReq.WXSceneTimeline // 使用传入的scene参数
+    req.message = mediaMessage
+
+    await WechatUtil.getWechatApi().sendReq(ContextHelper.UIAbilityContext, req)
+
+
   }
 
+
+  /**
+   * 微信分享
+   */
+  /**
+   * 微信分享
+   */
+  static async handleWeChatShareTest(shareData: ShareParams) {
+    let imageObject = new WXImageObject()
+
+    imageObject.uri = fileUri.getUriFromPath(await ImageUtil.downLoadToBox(shareData.imageUrl!));
+
+    let mediaMessage = new WXMediaMessage()
+    mediaMessage.mediaObject = imageObject
+
+    let req = new SendMessageToWXReq()
+    req.scene = SendMessageToWXReq.WXSceneSession
+    req.message = mediaMessage
+
+    await WechatUtil.getWechatApi().sendReq(ContextHelper.UIAbilityContext, req)
+  }
 }

+ 1 - 1
entry/src/main/ets/viewModels/JDBViewModel.ets

@@ -7,7 +7,7 @@ import { JDBObj, RunH5Param } from '../model/JDBModel'
 
 @ObservedV2
 export class JDBViewModel {
-  @Trace flag: boolean = true
+  @Trace flag: boolean = true //是否启动web
   @Trace isExistDeviceChannel: boolean = true
   controller: webview.WebviewController = new webview.WebviewController()
   host: string = ''