Closed giantss closed 8 years ago
我这也一样, android6.0. 可以识别微信安装与否, 调用分享时会闪一下一个页面就没有了.
我试了一下ios,ios上第一次分享是可以的,但是第二次分享弹出来了授权登录窗口,我点授权登录,退回到了我的app页面,然后弹出了"发送请求失败"
发送分享请求后,返回了,"未知错误".
这个图片是点击分享后控制台打印的信息,哥快出来看看啊
上面的图片是debug签名证书点击分享后控制台打印的信息,现在这个是发布签名证书点击分享后控制台打印的信息.
你这个bug和 #164 很像啊。是不是测试机的问题?
哦,我试试,我上面说的ios上的问题,你有没有遇到过呢
华为手机也试过了跟我一楼说的一样
@williambao , @giantss android闪一下,就是签名错了。
闪都没闪,后面两个方法都没返回东西,同样的代码在ios上第一次分享正常,第二次会弹出授权登录的窗口,我点授权登录,退回到了我的app页面,然后弹出了"发送请求失败"
晕,没人遇到过我这样的情况吗
我也遇上同样的问题了,不过我感觉是cordova5.0的问题,我把xuli的源码改啦,如下,找到protected boolean sendAuthRequest(CordovaArgs args, CallbackContext callbackContext) { final IWXAPI api = getWXAPI(); final SendAuth.Req req = new SendAuth.Req(); req.scope = "snsapi_userinfo"; req.state = "wechat"; // try { // req.scope = "snsapi_userinfo"; // req.state = "wechat"; // } catch (JSONException e) { // Log.e(TAG, e.getMessage()); // // req.scope = "snsapi_userinfo"; // req.state = "wechat"; // }
if (api.sendReq(req)) {
将try catch部分都注释掉,然后req.scope = "snsapi_userinfo"; req.state = "wechat";这样直接赋值就行。
这个trycatch与xuli的不同,因为我不断改,不知道xuli的原来代码是啥了
这是我的完整代码,添加了toast
package xu.li.cordova.wechat;
import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Environment; import android.util.Base64; import android.util.Log; import android.webkit.URLUtil; import android.widget.Toast; import android.os.Build;
import com.tencent.mm.sdk.modelmsg.SendAuth; import com.tencent.mm.sdk.modelmsg.SendMessageToWX; import com.tencent.mm.sdk.modelmsg.WXAppExtendObject; import com.tencent.mm.sdk.modelmsg.WXEmojiObject; import com.tencent.mm.sdk.modelmsg.WXFileObject; import com.tencent.mm.sdk.modelmsg.WXImageObject; import com.tencent.mm.sdk.modelmsg.WXMediaMessage; import com.tencent.mm.sdk.modelmsg.WXMusicObject; import com.tencent.mm.sdk.modelmsg.WXTextObject; 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.openapi.IWXAPI; import com.tencent.mm.sdk.openapi.WXAPIFactory;
import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaArgs; import org.apache.cordova.CordovaPlugin; import org.apache.cordova.PluginResult; import org.json.JSONException; import org.json.JSONObject;
import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream;
public class Wechat extends CordovaPlugin {
public static final String TAG = "Cordova.Plugin.Wechat";
public static final String WXAPPID_PROPERTY_KEY = "wechatappid";
public static final String ERROR_WECHAT_NOT_INSTALLED = "未安装微信";
public static final String ERROR_INVALID_PARAMETERS = "参数格式错误";
public static final String ERROR_SEND_REQUEST_FAILED = "发送请求失败";
public static final String ERROR_WECHAT_RESPONSE_COMMON = "普通错误";
public static final String ERROR_WECHAT_RESPONSE_USER_CANCEL = "用户点击取消并返回";
public static final String ERROR_WECHAT_RESPONSE_SENT_FAILED = "发送失败";
public static final String ERROR_WECHAT_RESPONSE_AUTH_DENIED = "授权失败";
public static final String ERROR_WECHAT_RESPONSE_UNSUPPORT = "微信不支持";
public static final String ERROR_WECHAT_RESPONSE_UNKNOWN = "未知错误";
public static final String EXTERNAL_STORAGE_IMAGE_PREFIX = "external://";
public static final String KEY_ARG_MESSAGE = "message";
public static final String KEY_ARG_SCENE = "scene";
public static final String KEY_ARG_TEXT = "text";
public static final String KEY_ARG_MESSAGE_TITLE = "title";
public static final String KEY_ARG_MESSAGE_DESCRIPTION = "description";
public static final String KEY_ARG_MESSAGE_THUMB = "thumb";
public static final String KEY_ARG_MESSAGE_MEDIA = "media";
public static final String KEY_ARG_MESSAGE_MEDIA_TYPE = "type";
public static final String KEY_ARG_MESSAGE_MEDIA_WEBPAGEURL = "webpageUrl";
public static final String KEY_ARG_MESSAGE_MEDIA_IMAGE = "image";
public static final String KEY_ARG_MESSAGE_MEDIA_TEXT = "text";
public static final String KEY_ARG_MESSAGE_MEDIA_MUSICURL = "musicUrl";
public static final String KEY_ARG_MESSAGE_MEDIA_MUSICDATAURL = "musicDataUrl";
public static final String KEY_ARG_MESSAGE_MEDIA_VIDEOURL = "videoUrl";
public static final String KEY_ARG_MESSAGE_MEDIA_FILE = "file";
public static final String KEY_ARG_MESSAGE_MEDIA_EMOTION = "emotion";
public static final String KEY_ARG_MESSAGE_MEDIA_EXTINFO = "extInfo";
public static final String KEY_ARG_MESSAGE_MEDIA_URL = "url";
public static final int TYPE_WECHAT_SHARING_APP = 1;
public static final int TYPE_WECHAT_SHARING_EMOTION = 2;
public static final int TYPE_WECHAT_SHARING_FILE = 3;
public static final int TYPE_WECHAT_SHARING_IMAGE = 4;
public static final int TYPE_WECHAT_SHARING_MUSIC = 5;
public static final int TYPE_WECHAT_SHARING_VIDEO = 6;
public static final int TYPE_WECHAT_SHARING_WEBPAGE = 7;
public static final int TYPE_WECHAT_SHARING_TEXT = 8;
public static final int SCENE_SESSION = 0;
public static final int SCENE_TIMELINE = 1;
public static final int SCENE_FAVORITE = 2;
public static final int MAX_THUMBNAIL_SIZE = 320;
public static Wechat instance = null;
protected CallbackContext currentCallbackContext;
protected IWXAPI wxAPI;
protected String appId;
private static final boolean IS_AT_LEAST_LOLLIPOP = Build.VERSION.SDK_INT >= 21;
@Override
protected void pluginInitialize() {
super.pluginInitialize();
instance = this;
initWXAPI();
Log.d(TAG, "plugin initialized.");
}
protected void initWXAPI() {
if (wxAPI == null) {
String appId = getAppId();
wxAPI = WXAPIFactory.createWXAPI(webView.getContext(), appId, true);
wxAPI.registerApp(appId);
}
}
public IWXAPI getWxAPI() {
return wxAPI;
}
public CallbackContext getCurrentCallbackContext() {
return currentCallbackContext;
}
@Override
public boolean execute(String action, CordovaArgs args, CallbackContext callbackContext) throws JSONException {
Log.d(TAG, String.format("%s is called. Callback ID: %s.", action, callbackContext.getCallbackId()));
if (action.equals("share")) {
return share(args, callbackContext);
} else if (action.equals("sendAuthRequest")) {
return sendAuthRequest(args, callbackContext);
} else if (action.equals("sendPaymentRequest")) {
return sendPaymentRequest(args, callbackContext);
} else if (action.equals("isWXAppInstalled")) {
return isInstalled(callbackContext);
}
return false;
}
protected boolean share(CordovaArgs args, final CallbackContext callbackContext)
throws JSONException {
final IWXAPI api = getWXAPI();
// check if installed
if (!api.isWXAppInstalled()) {
callbackContext.error(ERROR_WECHAT_NOT_INSTALLED);
return true;
}
// check if # of arguments is correct
final JSONObject params;
try {
params = args.getJSONObject(0);
} catch (JSONException e) {
callbackContext.error(ERROR_INVALID_PARAMETERS);
return true;
}
final SendMessageToWX.Req req = new SendMessageToWX.Req();
req.transaction = buildTransaction();
if (params.has(KEY_ARG_SCENE)) {
switch (params.getInt(KEY_ARG_SCENE)) {
case SCENE_FAVORITE:
req.scene = SendMessageToWX.Req.WXSceneFavorite;
break;
case SCENE_TIMELINE:
req.scene = SendMessageToWX.Req.WXSceneTimeline;
break;
case SCENE_SESSION:
req.scene = SendMessageToWX.Req.WXSceneSession;
break;
default:
req.scene = SendMessageToWX.Req.WXSceneTimeline;
}
} else {
req.scene = SendMessageToWX.Req.WXSceneTimeline;
}
// run in background
cordova.getThreadPool().execute(new Runnable() {
@Override
public void run() {
try {
req.message = buildSharingMessage(params);
} catch (JSONException e) {
Log.e(TAG, "Failed to build sharing message.", e);
// clear callback context
currentCallbackContext = null;
// send json exception error
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
}
if (api.sendReq(req)) {
Log.i(TAG, "Message has been sent successfully.");
} else {
Log.i(TAG, "Message has been sent unsuccessfully.");
// clear callback context
currentCallbackContext = null;
// send error
callbackContext.error(ERROR_SEND_REQUEST_FAILED);
}
}
});
// send no result
sendNoResultPluginResult(callbackContext);
return true;
}
protected boolean sendAuthRequest(CordovaArgs args, CallbackContext callbackContext) {
final IWXAPI api = getWXAPI();
final SendAuth.Req req = new SendAuth.Req();
req.scope = "snsapi_userinfo";
req.state = "wechat";
// try { // req.scope = "snsapi_userinfo"; // req.state = "wechat"; // } catch (JSONException e) { // Log.e(TAG, e.getMessage()); // // req.scope = "snsapi_userinfo"; // req.state = "wechat"; // }
if (api.sendReq(req)) {
Log.i(TAG, "Auth request has been sent successfully.");
Toast toast = Toast.makeText(IS_AT_LEAST_LOLLIPOP ? cordova.getActivity().getWindow().getContext() : cordova.getActivity().getApplicationContext(), "已发送", Toast.LENGTH_LONG);
toast.show();
// send no result
sendNoResultPluginResult(callbackContext);
} else {
Log.i(TAG, "Auth request has been sent unsuccessfully.");
Toast toast1 = Toast.makeText(IS_AT_LEAST_LOLLIPOP ? cordova.getActivity().getWindow().getContext() : cordova.getActivity().getApplicationContext(), "发送失败", Toast.LENGTH_LONG);
toast1.show();
// send error
callbackContext.error(ERROR_SEND_REQUEST_FAILED);
}
return true;
}
protected boolean sendPaymentRequest(CordovaArgs args, CallbackContext callbackContext) {
final IWXAPI api = getWXAPI();
// check if # of arguments is correct
final JSONObject params;
try {
params = args.getJSONObject(0);
} catch (JSONException e) {
callbackContext.error(ERROR_INVALID_PARAMETERS);
return true;
}
PayReq req = new PayReq();
try {
req.appId = getAppId();
req.partnerId = params.has("mch_id") ? params.getString("mch_id") : params.getString("partnerid");
req.prepayId = params.has("prepay_id") ? params.getString("prepay_id") : params.getString("prepayid");
req.nonceStr = params.has("nonce") ? params.getString("nonce") : params.getString("noncestr");
req.timeStamp = params.getString("timestamp");
req.sign = params.getString("sign");
req.packageValue = "Sign=WXPay";
} catch (Exception e) {
Log.e(TAG, e.getMessage());
callbackContext.error(ERROR_INVALID_PARAMETERS);
return true;
}
if (api.sendReq(req)) {
Log.i(TAG, "Payment request has been sent successfully.");
// send no result
sendNoResultPluginResult(callbackContext);
} else {
Log.i(TAG, "Payment request has been sent unsuccessfully.");
// send error
callbackContext.error(ERROR_SEND_REQUEST_FAILED);
}
return true;
}
protected boolean isInstalled(CallbackContext callbackContext) {
final IWXAPI api = getWXAPI();
if (!api.isWXAppInstalled()) {
callbackContext.success(0);
} else {
callbackContext.success(1);
}
return true;
}
protected WXMediaMessage buildSharingMessage(JSONObject params)
throws JSONException {
Log.d(TAG, "Start building message.");
// media parameters
WXMediaMessage.IMediaObject mediaObject = null;
WXMediaMessage wxMediaMessage = new WXMediaMessage();
if (params.has(KEY_ARG_TEXT)) {
WXTextObject textObject = new WXTextObject();
textObject.text = params.getString(KEY_ARG_TEXT);
mediaObject = textObject;
wxMediaMessage.description = textObject.text;
} else {
JSONObject message = params.getJSONObject(KEY_ARG_MESSAGE);
JSONObject media = message.getJSONObject(KEY_ARG_MESSAGE_MEDIA);
wxMediaMessage.title = message.getString(KEY_ARG_MESSAGE_TITLE);
wxMediaMessage.description = message.getString(KEY_ARG_MESSAGE_DESCRIPTION);
// thumbnail
Bitmap thumbnail = getThumbnail(message, KEY_ARG_MESSAGE_THUMB);
if (thumbnail != null) {
wxMediaMessage.setThumbImage(thumbnail);
thumbnail.recycle();
}
// check types
int type = media.has(KEY_ARG_MESSAGE_MEDIA_TYPE) ? media
.getInt(KEY_ARG_MESSAGE_MEDIA_TYPE) : TYPE_WECHAT_SHARING_WEBPAGE;
switch (type) {
case TYPE_WECHAT_SHARING_APP:
WXAppExtendObject appObject = new WXAppExtendObject();
appObject.extInfo = media.getString(KEY_ARG_MESSAGE_MEDIA_EXTINFO);
appObject.filePath = media.getString(KEY_ARG_MESSAGE_MEDIA_URL);
mediaObject = appObject;
break;
case TYPE_WECHAT_SHARING_EMOTION:
WXEmojiObject emoObject = new WXEmojiObject();
InputStream emoji = getFileInputStream(media.getString(KEY_ARG_MESSAGE_MEDIA_EMOTION));
if (emoji != null) {
try {
emoObject.emojiData = Util.readBytes(emoji);
} catch (IOException e) {
e.printStackTrace();
}
}
mediaObject = emoObject;
break;
case TYPE_WECHAT_SHARING_FILE:
WXFileObject fileObject = new WXFileObject();
fileObject.filePath = media.getString(KEY_ARG_MESSAGE_MEDIA_FILE);
mediaObject = fileObject;
break;
case TYPE_WECHAT_SHARING_IMAGE:
Bitmap image = getBitmap(message.getJSONObject(KEY_ARG_MESSAGE_MEDIA), KEY_ARG_MESSAGE_MEDIA_IMAGE, 0);
mediaObject = new WXImageObject(image);
image.recycle();
break;
case TYPE_WECHAT_SHARING_MUSIC:
WXMusicObject musicObject = new WXMusicObject();
musicObject.musicUrl = media.getString(KEY_ARG_MESSAGE_MEDIA_MUSICURL);
musicObject.musicDataUrl = media.getString(KEY_ARG_MESSAGE_MEDIA_MUSICDATAURL);
mediaObject = musicObject;
break;
case TYPE_WECHAT_SHARING_VIDEO:
WXVideoObject videoObject = new WXVideoObject();
videoObject.videoUrl = media.getString(KEY_ARG_MESSAGE_MEDIA_VIDEOURL);
mediaObject = videoObject;
break;
case TYPE_WECHAT_SHARING_WEBPAGE:
default:
mediaObject = new WXWebpageObject(media.getString(KEY_ARG_MESSAGE_MEDIA_WEBPAGEURL));
}
}
wxMediaMessage.mediaObject = mediaObject;
return wxMediaMessage;
}
protected IWXAPI getWXAPI() {
return wxAPI;
}
private String buildTransaction() {
return String.valueOf(System.currentTimeMillis());
}
private String buildTransaction(final String type) {
return type + System.currentTimeMillis();
}
protected Bitmap getThumbnail(JSONObject message, String key) {
return getBitmap(message, key, MAX_THUMBNAIL_SIZE);
}
protected Bitmap getBitmap(JSONObject message, String key, int maxSize) {
Bitmap bmp = null;
String url = null;
try {
if (!message.has(key)) {
return null;
}
url = message.getString(key);
// get input stream
InputStream inputStream = getFileInputStream(url);
if (inputStream == null) {
return null;
}
// decode it
// @TODO make sure the image is not too big, or it will cause out of memory
BitmapFactory.Options options = new BitmapFactory.Options();
bmp = BitmapFactory.decodeStream(inputStream, null, options);
// scale
if (maxSize > 0 && (options.outWidth > maxSize || options.outHeight > maxSize)) {
Log.d(TAG, String.format("Bitmap was decoded, dimension: %d x %d, max allowed size: %d.",
options.outWidth, options.outHeight, maxSize));
int width = 0;
int height = 0;
if (options.outWidth > options.outHeight) {
width = maxSize;
height = width * options.outHeight / options.outWidth;
} else {
height = maxSize;
width = height * options.outWidth / options.outHeight;
}
Bitmap scaled = Bitmap.createScaledBitmap(bmp, width, height, true);
bmp.recycle();
bmp = scaled;
}
inputStream.close();
} catch (JSONException e) {
bmp = null;
e.printStackTrace();
} catch (IOException e) {
bmp = null;
e.printStackTrace();
}
return bmp;
}
/**
* Get input stream from a url
*
* @param url
* @return
*/
protected InputStream getFileInputStream(String url) {
try {
InputStream inputStream = null;
if (URLUtil.isHttpUrl(url) || URLUtil.isHttpsUrl(url)) {
File file = Util.downloadAndCacheFile(webView.getContext(), url);
if (file == null) {
Log.d(TAG, String.format("File could not be downloaded from %s.", url));
return null;
}
url = file.getAbsolutePath();
inputStream = new FileInputStream(file);
Log.d(TAG, String.format("File was downloaded and cached to %s.", url));
} else if (url.startsWith("data:image")) { // base64 image
String imageDataBytes = url.substring(url.indexOf(",") + 1);
byte imageBytes[] = Base64.decode(imageDataBytes.getBytes(), Base64.DEFAULT);
inputStream = new ByteArrayInputStream(imageBytes);
Log.d(TAG, "Image is in base64 format.");
} else if (url.startsWith(EXTERNAL_STORAGE_IMAGE_PREFIX)) { // external path
url = Environment.getExternalStorageDirectory().getAbsolutePath() + url.substring(EXTERNAL_STORAGE_IMAGE_PREFIX.length());
inputStream = new FileInputStream(url);
Log.d(TAG, String.format("File is located on external storage at %s.", url));
} else if (!url.startsWith("/")) { // relative path
inputStream = cordova.getActivity().getApplicationContext().getAssets().open(url);
Log.d(TAG, String.format("File is located in assets folder at %s.", url));
} else {
inputStream = new FileInputStream(url);
Log.d(TAG, String.format("File is located at %s.", url));
}
return inputStream;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
protected String getAppId() {
if (this.appId == null) {
this.appId = preferences.getString(WXAPPID_PROPERTY_KEY, "");
}
return this.appId;
}
private void sendNoResultPluginResult(CallbackContext callbackContext) {
// save current callback context
currentCallbackContext = callbackContext;
// send no result and keep callback
PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT);
result.setKeepCallback(true);
callbackContext.sendPluginResult(result);
}
}
楼上留个联系方式行吗 QQ谢谢
额,我仔细看了一下我的那个README里面的实例代码。其实scope参数是不需要的,默认就是snsapi_userinfo。当初加在README里面,只是为了告诉大家,可以传scope。
@giantss
首先,你用的什么版本的cordova-plugin-wechat?最新版的代码不是这样的。 其次,返回了-6,你应该去找微信,为什么他们会返回-6? 最后,我的switch的语句,目的是转换微信的error code到我自定义的error code (因为我还有其它的error code要返回,比如参数错误)。
我擦,签名问题.重新申请了一个应用填写资料好了
Wechat.isInstalled 返回了 YES
Wechat.auth 没返回任何消息
Wechat.share 没返回任何消息