Skip to content

添加微信朋友圈分享功能 #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,38 @@ DeviceEventEmitter.addListener('finishedShare',function(event){
});
```

#### WechatAPI.shareToTimeline(data)
分享到朋友圈

```javascript
// 分享文字
{
type: 'text',
text: 文字内容,
}
```

```javascript
// 分享图片
{
type: 'image',
imageUrl: 图片地址,
title : 标题,
description : 描述,
}
```

```javascript
// 分享网页
{
type: 'news',
title : 标题,
description : 描述,
webpageUrl : 链接地址,
imageUrl: 缩略图地址,
}
```

### weChatPay(options,callback)

options : [微信支付需要的参数](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12&index=2)
Expand Down
316 changes: 315 additions & 1 deletion android/src/main/java/com/heng/wechat/WeChatModule.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,45 @@
package com.heng.wechat;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.text.TextUtils;

import android.util.Log;

import com.facebook.common.executors.UiThreadImmediateExecutorService;
import com.facebook.common.internal.Preconditions;
import com.facebook.common.references.CloseableReference;
import com.facebook.common.util.UriUtil;
import com.facebook.datasource.BaseDataSubscriber;
import com.facebook.datasource.DataSource;
import com.facebook.datasource.DataSubscriber;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.drawable.OrientedDrawable;
import com.facebook.imagepipeline.common.ResizeOptions;
import com.facebook.imagepipeline.core.ImagePipeline;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.image.CloseableStaticBitmap;
import com.facebook.imagepipeline.image.EncodedImage;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.RCTNativeAppEventEmitter;
import com.tencent.mm.sdk.modelbase.BaseReq;
import com.tencent.mm.sdk.modelbase.BaseResp;
import com.tencent.mm.sdk.modelmsg.SendAuth;
import com.tencent.mm.sdk.modelmsg.SendMessageToWX;
import com.tencent.mm.sdk.modelmsg.WXImageObject;
Expand All @@ -18,6 +49,7 @@
import com.tencent.mm.sdk.modelmsg.WXVideoObject;
import com.tencent.mm.sdk.modelmsg.WXWebpageObject;
import com.tencent.mm.sdk.modelpay.PayReq;
import com.tencent.mm.sdk.modelpay.PayResp;
import com.tencent.mm.sdk.openapi.IWXAPI;
import com.tencent.mm.sdk.openapi.WXAPIFactory;

Expand Down Expand Up @@ -90,6 +122,23 @@ public class WeChatModule extends ReactContextBaseJavaModule {
public static final String OPTIONS_SIGN = "sign";
/*============ WeChat pay options key ==============*/

private static final String RCTWXShareTypeNews = "news";
private static final String RCTWXShareTypeImage = "image";
private static final String RCTWXShareTypeText = "text";
private static final String RCTWXShareTypeVideo = "video";
private static final String RCTWXShareTypeAudio = "audio";

private static final String RCTWXShareType = "type";
private static final String RCTWXShareText = "text";
private static final String RCTWXShareTitle = "title";
private static final String RCTWXShareDescription = "description";
private static final String RCTWXShareWebpageUrl = "webpageUrl";
private static final String RCTWXShareImageUrl = "imageUrl";
private static final String RCTWXShareThumbImageSize = "thumbImageSize";

private final static String NOT_REGISTERED = "registerApp required.";
private final static String INVOKE_FAILED = "WeChat API invoke returns false.";


public static final int TYPE_TEXT = 1; //文字
public static final int TYPE_IMAGE = 2; //图片
Expand Down Expand Up @@ -311,6 +360,14 @@ public void sendReq(ReadableMap options, Callback callback) {
}
}

/**
* 分享到朋友圈
*/
@ReactMethod
public void shareToTimeline(ReadableMap data, Callback callback) {
_share(SendMessageToWX.Req.WXSceneTimeline, data, callback);
}


/**
* 微信支付
Expand Down Expand Up @@ -495,4 +552,261 @@ private WXVideoObject getVideoObj(ReadableMap options){
return videoObject;
}


/**
* 分享到微信
* */
@ReactMethod
public void shareToSession(ReadableMap data, Callback callback){
_share(SendMessageToWX.Req.WXSceneSession, data, callback);
}


private String _getErrorMsg(int errCode) {
switch (errCode) {
case BaseResp.ErrCode.ERR_OK:
return "成功";
case BaseResp.ErrCode.ERR_COMM:
return "普通错误类型";
case BaseResp.ErrCode.ERR_USER_CANCEL:
return "用户点击取消并返回";
case BaseResp.ErrCode.ERR_SENT_FAILED:
return "发送失败";
case BaseResp.ErrCode.ERR_AUTH_DENIED:
return "授权失败";
case BaseResp.ErrCode.ERR_UNSUPPORT:
return "微信不支持";
default:
return "失败";
}
}


private void _share(final int scene, final ReadableMap data, final Callback callBack){

if (data.hasKey(RCTWXShareImageUrl)) {
String imageUrl = data.getString(RCTWXShareImageUrl);
DataSubscriber<CloseableReference<CloseableImage>> dataSubscriber =
new BaseDataSubscriber<CloseableReference<CloseableImage>>() {
@Override
public void onNewResultImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
// isFinished must be obtained before image, otherwise we might set intermediate result
// as final image.
boolean isFinished = dataSource.isFinished();
// float progress = dataSource.getProgress();
CloseableReference<CloseableImage> image = dataSource.getResult();
if (image != null) {
Drawable drawable = _createDrawable(image);
Bitmap bitmap = _drawable2Bitmap(drawable);
_share(scene, data, bitmap, callBack);
} else if (isFinished) {
_share(scene, data, null, callBack);
}
dataSource.close();
}
@Override
public void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
dataSource.close();
_share(scene, data, null, callBack);
}

@Override
public void onProgressUpdate(DataSource<CloseableReference<CloseableImage>> dataSource) {
}
};
ResizeOptions resizeOptions = null;
if (!(data.hasKey(RCTWXShareType) && data.getString(RCTWXShareType).equals(RCTWXShareTypeImage))) {
int size = 80;
if (data.hasKey(RCTWXShareThumbImageSize)) {
size = data.getInt(RCTWXShareThumbImageSize);
}
resizeOptions = new ResizeOptions(size, size);
}
_downloadImage(imageUrl, resizeOptions, dataSubscriber);
}
else {
_share(scene, data, null, callBack);
}
}

private void _share(int scene, ReadableMap data, Bitmap image, Callback callback) {
WXMediaMessage message = new WXMediaMessage();
if (data.hasKey(RCTWXShareTitle)){
message.title = data.getString(RCTWXShareTitle);
}
if (data.hasKey(RCTWXShareDescription)) {
message.description = data.getString(RCTWXShareDescription);
}

String type = RCTWXShareTypeNews;
if (data.hasKey(RCTWXShareType)) {
type = data.getString(RCTWXShareType);
}

if (type.equals(RCTWXShareTypeText)) {
WXTextObject object = new WXTextObject();
if (data.hasKey(RCTWXShareText)) {
object.text = data.getString(RCTWXShareText);
}
message.mediaObject = object;
}
else if (type.equals(RCTWXShareTypeImage)) {
WXImageObject object = new WXImageObject();
if (data.hasKey(RCTWXShareImageUrl)) {
if (image != null) {
object.imageData = _Bitmap2Bytes(image);
Bitmap thumb = Bitmap.createScaledBitmap(image, 80, 80, true);
message.thumbData = _Bitmap2Bytes(thumb);
}
}
message.mediaObject = object;
}
else {
if (type.equals(RCTWXShareTypeNews)) {
WXWebpageObject object = new WXWebpageObject();
if (data.hasKey(RCTWXShareWebpageUrl)){
object.webpageUrl = data.getString(RCTWXShareWebpageUrl);
}
if (data.hasKey("extInfo")){
object.extInfo = data.getString("extInfo");
}
message.mediaObject = object;
}
else if (type.equals(RCTWXShareTypeVideo)) {
WXMusicObject object = new WXMusicObject();
if (data.hasKey(RCTWXShareWebpageUrl)) {
object.musicUrl = data.getString(RCTWXShareWebpageUrl);
}
message.mediaObject = object;
}
else if (type.equals(RCTWXShareTypeAudio)) {
WXVideoObject object = new WXVideoObject();
if (data.hasKey(RCTWXShareWebpageUrl)) {
object.videoUrl = data.getString(RCTWXShareWebpageUrl);
}
message.mediaObject = object;
}

if (image != null) {
Log.e("share", "image no null");
message.setThumbImage(image);
}else {
Log.e("share", "image null");
}
}

//TODO: create Thumb Data.
if (data.hasKey("mediaTagName")) {
message.mediaTagName = data.getString("mediaTagName");
}
if (data.hasKey("messageAction")) {
message.mediaTagName = data.getString("messageAction");
}
if (data.hasKey("messageExt")) {
message.mediaTagName = data.getString("messageExt");
}

SendMessageToWX.Req req = new SendMessageToWX.Req();
req.message = message;
req.scene = scene;

boolean success = WeChatModule.wxApi.sendReq(req);

if (success == false) {
callback.invoke("INVOKE_FAILED");
}else {
callback.invoke();
}

}

private static @Nullable
Uri getResourceDrawableUri(Context context, @Nullable String name) {
if (name == null || name.isEmpty()) {
return null;
}
name = name.toLowerCase().replace("-", "_");
int resId = context.getResources().getIdentifier(
name,
"drawable",
context.getPackageName());
return new Uri.Builder()
.scheme(UriUtil.LOCAL_RESOURCE_SCHEME)
.path(String.valueOf(resId))
.build();
}

private void _downloadImage(String imageUrl, ResizeOptions resizeOptions, DataSubscriber<CloseableReference<CloseableImage>> dataSubscriber) {

Uri uri = null;
try {
uri = Uri.parse(imageUrl);
// Verify scheme is set, so that relative uri (used by static resources) are not handled.
if (uri.getScheme() == null) {
uri = null;
}
} catch (Exception e) {
// ignore malformed uri, then attempt to extract resource ID.
}
if (uri == null) {
uri = getResourceDrawableUri(getReactApplicationContext(), imageUrl);
} else {
}

ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri);
if (resizeOptions != null) {
builder = builder.setResizeOptions(resizeOptions);
}
ImageRequest imageRequest = builder.build();

ImagePipeline imagePipeline = Fresco.getImagePipeline();
DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, null);
dataSource.subscribe(dataSubscriber, UiThreadImmediateExecutorService.getInstance());
}

private Drawable _createDrawable(CloseableReference<CloseableImage> image) {
Preconditions.checkState(CloseableReference.isValid(image));
CloseableImage closeableImage = image.get();
if (closeableImage instanceof CloseableStaticBitmap) {
CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) closeableImage;
BitmapDrawable bitmapDrawable = new BitmapDrawable(
getReactApplicationContext().getResources(),
closeableStaticBitmap.getUnderlyingBitmap());
if (closeableStaticBitmap.getRotationAngle() == 0 ||
closeableStaticBitmap.getRotationAngle() == EncodedImage.UNKNOWN_ROTATION_ANGLE) {
return bitmapDrawable;
} else {
return new OrientedDrawable(bitmapDrawable, closeableStaticBitmap.getRotationAngle());
}
} else {
throw new UnsupportedOperationException("Unrecognized image class: " + closeableImage);
}
}

private Bitmap _drawable2Bitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
} else if (drawable instanceof NinePatchDrawable) {
Bitmap bitmap = Bitmap
.createBitmap(
drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(),
drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
: Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight());
drawable.draw(canvas);
return bitmap;
} else {
return null;
}
}

private byte[] _Bitmap2Bytes(Bitmap bm){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 70, baos);
return baos.toByteArray();
}

}