Xamarin是微软旗下的一款跨平台移动开发框架,开发移动应用还算不错,但是在中国的应用一般避免不了微信和支付宝,所以我打算结合网上能找到的资料,写几篇文章,帮助大家避坑。
本文主要讲微信登录,我暂时还未实现微信支付,所以暂时不讲。
不过,我的同学已经详细地讲解了微信分享,地址在这儿—>https://blog.csdn.net/hgp0487561/article/details/104341094
一、准备工作
首先,我们要引入微信SDK。Xamarin是可以调用Java代码的,但是Java代码必须包装一下,在项目中引入就可以了。
这样有个优点就是很多网上能找的Java示例代码在C#中小改就可以用了。
给大家提供我已经打包好的微信SDK,地址在这儿—>https://github.com/CrazyPhilip/WeChatClassLibrary/releases/tag/v1.0
然后,appID是必须的,如何申请也不再多说。
二、编写代码
Xamarin.Forms与Android之间还是存在一定“鸿沟”的,所以,要想调用写在XXX.Droid项目中的代码时,可以用MessengingCenter。
注:代码中XXX表示项目名。
第一步,在MainActivity.cs中加入如下代码:
using Com.Tencent.MM.Opensdk.Modelmsg;
using Com.Tencent.MM.Opensdk.Openapi;
using Com.Tencent.Smtt.Sdk;
namespace XXX.Droid
{
[Activity(MainLauncher = false, Label = "app名字", Icon = "@mipmap/icon", Theme = "@style/MainTheme", ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
//微信相关的成员变量
private readonly string appID = "aaaaaaaaaaaaa"; //申请的appid
private IWXAPI wxApi;
protected override void OnCreate(Bundle savedInstanceState)
{
//其他代码块
#region 微信相关
//注册到微信,相当于初始化
MessagingCenter.Subscribe<object>(this, "Register", d =>
{
var result = RegToWx();
});
//微信登录
MessagingCenter.Subscribe<object>(this, "Login", d =>
{
// send oauth request,Scope不要改动,是表示你要请求哪些数据的意思,State可以改动,表示其他信息
SendAuth.Req req = new SendAuth.Req()
{
Scope = "snsapi_userinfo",
State = "xxx_wechat_login"
};
bool result = wxApi.SendReq(req); //想微信发送请求
});
#endregion
//其他代码块
}
//微信初始化
private bool RegToWx()
{
wxApi = WXAPIFactory.CreateWXAPI(this, appID, true);
return wxApi.RegisterApp(appID);
}
}
}
第二步,在XXX.Droid项目中新建一个文件夹,命名为wxapi。文件夹下新建一个WXEntryActivity类。
注意:这个Activity头部的注解中,Name属性必须!!!是程序包名+文件夹名+文件名,例如com.companyname.XXX是程序包名(AndroidManifest.xml中package属性),加上文件路径。这样微信回调的时候才能找到回调方法。
using Android;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Util;
using Android.Widget;
using Com.Tencent.MM.Opensdk.Constants;
using Com.Tencent.MM.Opensdk.Modelbase;
using Com.Tencent.MM.Opensdk.Modelmsg;
using Com.Tencent.MM.Opensdk.Openapi;
using Org.Json;
using Plugin.Toast;
using System;
using Exception = Java.Lang.Exception;
using XXX.Services;
using Xamarin.Forms;
namespace XXX.Droid.wxapi
{
[Activity(Name = "com.companyname.XXX.wxapi.WXEntryActivity", Label = "@string/app_name", Exported = true,
LaunchMode = Android.Content.PM.LaunchMode.SingleTop, TaskAffinity = "XXX")]
public class WXEntryActivity : Activity, IWXAPIEventHandler
{
private readonly string appID = "aaaaaaaaaaaaa";//填入自己申请的appid
private readonly string appSecret = "bbbbbbbbbbbbbbbbbbbbbbbb";//填入对应的appSecret
private MyHandler handler;
private string TAG = "MyHandler";
private IWXAPI api;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
api = WXAPIFactory.CreateWXAPI(this, appID, true);
handler = new MyHandler(this);
try
{
Intent intent = this.Intent;
bool b = api.HandleIntent(intent, this);
}
catch (Exception e)
{
Log.Error(TAG, e.StackTrace);
}
}
public new void Dispose()
{
this.Dispose();
}
protected void onNewIntent(Intent intent)
{
base.OnNewIntent(intent);
this.Intent = intent;
api.HandleIntent(intent, this);
}
// 微信发送请求到第三方应用时,会回调到该方法
public void OnReq(BaseReq req)
{
switch (req.Type)
{
case ConstantsAPI.CommandSendauth:
break;
case ConstantsAPI.CommandGetmessageFromWx:
break;
case ConstantsAPI.CommandShowmessageFromWx:
break;
default:
break;
}
}
// 第三方应用发送到微信的请求处理后的响应结果,会回调到该方法
public void OnResp(BaseResp resp)
{
const int RETURN_MSG_TYPE_LOGIN = 1;
const int RETURN_MSG_TYPE_SHARE = 2;
Console.Write("微信回调成功");
//CrossToastPopUp.Current.ShowToastSuccess("微信回调成功", Plugin.Toast.Abstractions.ToastLength.Short);
switch (resp.MyErrCode)
{
case BaseResp.ErrCode.ErrAuthDenied:
Console.Write("用户拒绝授权");
//CrossToastPopUp.Current.ShowToastError("用户拒绝授权", Plugin.Toast.Abstractions.ToastLength.Short);
Finish();
break;
case BaseResp.ErrCode.ErrUserCancel:
if (RETURN_MSG_TYPE_SHARE == resp.Type)
Console.Write("分享失败");
//CrossToastPopUp.Current.ShowToastError("分享失败", Plugin.Toast.Abstractions.ToastLength.Short);
else
Console.Write("用户取消");
//CrossToastPopUp.Current.ShowToastError("用户取消", Plugin.Toast.Abstractions.ToastLength.Short);
Finish();
break;
case BaseResp.ErrCode.ErrOk:
switch (resp.Type)
{
case RETURN_MSG_TYPE_LOGIN:
//拿到了微信返回的code,立马再去请求access_token
string code = ((SendAuth.Resp)resp).Code;
//就在这个地方,用网络库什么的或者自己封的网络api,发请求去咯,注意是get请求
string result = RestSharpService.GetWechatUserInfo(appID, appSecret, code);
//用MessagingCenter.Send()方法将上面获取的用户信息返回到你最开始发起请求的地方(下面第三步)
//注意,要用RunOnUiThread()方法,不然会出现卡顿等乱七八糟的问题。
RunOnUiThread(() => { MessagingCenter.Send(new object(), "LoginSuccess", result); });
break;
case RETURN_MSG_TYPE_SHARE:
Console.Write("分享");
//CrossToastPopUp.Current.ShowToastSuccess("分享", Plugin.Toast.Abstractions.ToastLength.Short);
Finish();
break;
}
Finish();
break;
default:
Finish();
break;
}
}
class MyHandler : Handler
{
private string TAG = "MyHandler";
private WeakReference<WXEntryActivity> wxEntryActivityWeakReference;
public MyHandler(WXEntryActivity wxEntryActivity)
{
wxEntryActivityWeakReference = new WeakReference<WXEntryActivity>(wxEntryActivity);
}
public void handleMessage(Message msg)
{
//int tag = msg.What;
Bundle data = msg.Data;
try
{
JSONObject json = new JSONObject(data.GetString("result"));
string openId, accessToken, refreshToken, scope;
openId = json.GetString("openid");
accessToken = json.GetString("access_token");
refreshToken = json.GetString("refresh_token");
scope = json.GetString("scope");
WXEntryActivity wxentry;
wxEntryActivityWeakReference.TryGetTarget(out wxentry);
Intent intent = new Intent(wxentry, typeof(WXEntryActivity));
intent.PutExtra("openId", openId);
intent.PutExtra("accessToken", accessToken);
intent.PutExtra("refreshToken", refreshToken);
intent.PutExtra("scope", scope);
wxentry.StartActivity(intent);
}
catch (JSONException ex)
{
Log.Error(TAG, ex.Message);
}
}
}
}
}
第三步,在你的Xamarin.Forms项目中,响应“微信登录”点击事件的地方调用MainActivity中注册的的“Login”事件。
例如如下代码就是在LoginPage.xaml.cs中的响应“微信登录”按钮点击事件的方法中。也可以写在对应ViewModel的Command中。
private void Button_Clicked(object sender, EventArgs e)
{
MessagingCenter.Send(new object(), "Register");//首先进行注册,然后订阅注册的结果。
MessagingCenter.Send(new object(), "Login");
//微信登录成功,返回用户信息
MessagingCenter.Subscribe<object, string>(this, "LoginSuccess", async (sender, result) =>
{
try
{
//利用用户信息做接下来的事
//JObject jObject = JObject.Parse(result);
//RegisterByOpenIdPara registerByOpenIdPara = new RegisterByOpenIdPara
//{
// openId = jObject["openid"].ToString(),
// nikename = jObject["nickname"].ToString(),
// headimgurl = jObject["headimgurl"].ToString(),
//};
//BindingWechatPage bindingWechatPage = new BindingWechatPage(registerByOpenIdPara);
//await Application.Current.MainPage.Navigation.PushAsync(bindingWechatPage);
//MessagingCenter.Unsubscribe<object, string>(this, "LoginSuccess");
//MessagingCenter.Unsubscribe<object, string>(this, "Login");
}
catch (Exception ex)
{
Console.WriteLine("错误:" + ex);
}
});
}
不出意外应该就可以正确登录了。
整个流程大概就是LoginPage.xaml.cs中发起登录—(通过MessagingCenter)—>调用注册在MainActivity.cs中的“Login”事件,“Login”事件中向微信发起请求------>跳转到微信页面,用户点击“同意”后------>自动跳回app去调用回调函数—(通过MessagingCenter)—>回到注册在LoginPage.xaml.cs中的“LoginSuccess”事件。
经验不足,水平有限,有错误或者可以优化的地方欢迎大家指证。