Xamarin.Forms实现微信登录

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”事件。

经验不足,水平有限,有错误或者可以优化的地方欢迎大家指证。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值