第三方登录踩坑记录

本文介绍了在Android应用中集成第三方登录(如QQ、微信)时遇到的签名配置问题和回调接收问题。开发者需要处理不同环境下的签名切换,以及在微信和QQSDK中如何正确设置回调以获取登录授权信息。此外,文章还提到了图片分享时的文件权限问题,需通过FileProvider解决。
摘要由CSDN通过智能技术生成

背景

最近做了注册登录的功能,其中涉及到第三方登录,就是通过 QQ 或微信或 FaceBook 等的账号进行登录。这种通过第三方的账号进行登录的逻辑都差不多,就是通过第三方的 sdk 拿到对应的 token,然后再用 token 向自己的业务后台进行注册,后台可以通过 token 获取到第三方平台的用户信息。

具体的流程如下图所示,其中 QQ 登录的路径和其他任何第三方登录的路径是一样的。
在这里插入图片描述
在接入第三方登录的过程当中踩了一些坑,这里记录一下。

遇到的坑

签名问题

第三方登录的时候需要先在对应的网站上注册自己的 appid,注册的时候就需要提供应用的签名。一般我们的应用会有两个签名,正式签名和测试签名,所以这里最好在网站上注册两个 appid,分别对应正式签名和测试签名,这样就不用来回切换,特别是像微信,每次修改一下都需要审核,就非常的麻烦。appid 注册好了之后,我们在应用内部进行判断,debug 版使用测试签名,release 版使用正式签名。

另外,这里博主还遇到了另外一个问题,由于应用的签名是从公司内网获取的,没办法直接看到 release 版本的签名信息,所以可以在 App 内部运行一段代码,将当前的签名信息打印出来。

执行 getSign 方法就可以获取到当前应用的签名信息了。


    public static String getSign(Context context) {
        PackageManager manager = context.getPackageManager();
        /** 通过包管理器获得指定包名包含签名的包信息 **/
        PackageInfo packageInfo = null;
        try {
            packageInfo = manager.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        /******* 通过返回的包信息获得签名数组 *******/
        Signature[] signatures = packageInfo.signatures;
        String ss = hexdigest(signatures[0].toByteArray());
        return ss;
    }

    private static final char[] hexDigits = { 48, 49, 50, 51, 52, 53, 54, 55,
            56, 57, 97, 98, 99, 100, 101, 102 };

    private static String hexdigest(String paramString) {
        try {
            String str = hexdigest(paramString.getBytes());
            return str;
        } catch (Exception localException) {
        }
        return null;
    }

    private static String hexdigest(byte[] paramArrayOfByte) {
        try {
            MessageDigest localMessageDigest = MessageDigest.getInstance("MD5");
            localMessageDigest.update(paramArrayOfByte);
            byte[] arrayOfByte = localMessageDigest.digest();
            char[] arrayOfChar = new char[32];
            int i = 0;
            int j = 0;
            while (true) {
                if (i >= 16)
                    return new String(arrayOfChar);
                int k = arrayOfByte[i];
                int m = j + 1;
                arrayOfChar[j] = hexDigits[(0xF & k >>> 4)];
                j = m + 1;
                arrayOfChar[m] = hexDigits[(k & 0xF)];
                i++;
            }
        } catch (Exception localException) {
        }
        return null;
    }
收不到回调

在接入微信和 QQ sdk 的时候就遇到了这样的问题,死活收不到回调,感觉按照官网的步骤一步一步的配置了,但就是收不到回调信息。
按照我的理解,调用 sdk 的登录授权功能,应该是这样:


val sdkinstance = SDKInstance(appid)
sdkinstance.login(context,object:listener{
   override fun onComplete(p0: Any?) {
       Log.i(TAG, "onComplete,${p0}")
   }

   override fun onError(errorCode:Int, errorMsg:String) {
       Log.i(TAG, "onError,errorCode:${errorCode},errorMsg:${errorMsg}")
      
   }
})

直接调用一下 sdk 的初始化方法,然后塞入一个回调方法,然后就可以在回调方法里面获取到结果了,但事实上并没有想的这么简单。

微信 sdk 获取到回调

想要微信 sdk 获取到回调信息,需要创建一个 WXEntryActivity,其包名必须为 ${applicationId}.wxapi
在这里插入图片描述
让 WXEntryActivity 继承 IWXAPIEventHandler 接口,或者创建一个 IWXAPIEventHandler 的成员变量,
然后在其 onCreate 和 onNewIntent 的生命周期方法里面将处这个 handler 塞进 sdk 当中,这样就可以获取到回调了。

public class WXEntryActivity extends Activity implements IWXAPIEventHandler {

    private static String TAG = "MicroMsg.WXEntryActivity";

    private IWXAPI api;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        api = WechatLogin.INSTANCE.getWechatApi();
        try {
            Intent intent = getIntent();
            api.handleIntent(intent, this);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        api.handleIntent(intent, this);
    }

    @Override
    public void onResp(BaseResp resp) {
       //这里收到回调
    }
}

QQ sdk 获取到回调

获取到 QQ sdk 的回调也没有那么直接,需要在对应的 activity 的 onActivityResult 里面设置一下监听方法才能收到。

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    Log.d(TAG, "-->onActivityResult $requestCode resultCode=$resultCode")
    when (requestCode) {
        Constants.REQUEST_LOGIN,
        Constants.REQUEST_QQ_SHARE,
        Constants.REQUEST_APPBAR -> {
            Tencent.onActivityResultData(
                requestCode,
                resultCode,
                data,
                QQLogin.delegateListener
            )
        }
        else -> {}
    }
    super.onActivityResult(requestCode, resultCode, data)
    finish()
}

所以这里可以创建一个透明的 activity,用作代理,这样调用起来就会比较方便。

图片分享

接入 sdk 之后调用图片分享,就遇到了下面的问题。
在这里插入图片描述
经过排查,发现是文件路径没有权限的问题,分享的图片在应用的私有目录,其他的应用没有权限读到,所以还必须要配置 FileProvider 属性。

 <provider
     android:authorities="com.tencent.sample.fileprovider"
     android:name="androidx.core.content.FileProvider"
     android:exported="false"
     android:grantUriPermissions="true"
     >
     <meta-data
         android:name="android.support.FILE_PROVIDER_PATHS"
         android:resource="@xml/file_paths"/>
 </provider>

file_paths:

<paths>
    <external-files-path name="opensdk_external" path="Images/tmp"/>
    <root-path name="opensdk_root" path=""/>
</paths>

所以我们分享图片的时候,需要将原有的图片复制到分享的目录,这样其他的应用才能够读到。

 //将bitmap写入分享目录
 fun copyBitmapToSharePath(bitmap: Bitmap): String {
     val file = createShareFile()
     file.outputStream().let {
         bitmap?.compress(Bitmap.CompressFormat.PNG, 100, it)
     }
     return file.absolutePath
 }

//将图片文件写入分享目录
fun copyImgToSharePath(imgPath: String): String? {
    val imgFile = File(imgPath)
    if (!imgFile.exists()){
        return null
    }
    val outputFile = createShareFile()
    imgFile.inputStream().use {
        it.copyTo(outputFile.outputStream())
    }
    return outputFile.absolutePath
}

private fun createShareFile(): File {
    val uuid = UUID.randomUUID()
    val path =
        BaseApplication.context.getExternalFilesDir("Images")!!.absolutePath + "/tmp/${uuid}"
    val file = File(path)
    if (file.exists()) {
        file.delete()
    }
    if (!file.parentFile.exists()) {
        file.parentFile.mkdirs()
    }
    file.createNewFile()
    return file
}

总结

在进行任务初评的时候,感觉接入 sdk 应该花不了多长时间,一天最多两天的就能搞定,但事实上还是花了三四天时间。特别是回调的方式,用起来总感觉不是那么的得劲儿,不知道是因为历史原因还是有什么其他方面的考量,为什么不能够简单直接的塞个 callback ,业务层只需要在 callback 里面获得结果就行了呢?

在Node.js中安装第三方库有多种方式。一种常见的方式是使用npm(Node Package Manager)来安装库。npm是Node.js的包管理工具,它允许您在项目中添加,更新和删除依赖项。 要安装一个第三方库,您可以在终端中使用以下命令: npm install 库名称 例如,如果要安装名为"express"的库,您可以运行以下命令: npm install express 此命令将从npm仓库下载并安装"express"库及其相关依赖项。安装完成后,您就可以在您的Node.js项目中使用该库了。 另一种常见的方式是手动下载库的源代码或二进制文件,并将其添加到您的项目中。这种方式适用于一些没有发布到npm仓库的库,或者您需要使用特定版本的库。 例如,您可以从库的GitHub页面上下载源代码,并将其放置在您的项目目录中的相应位置。然后,您可以在您的代码中使用require函数来引入该库。 请注意,无论使用哪种方式安装库,您都需要在代码中明确引入该库,并按照库的文档和示例来正确使用它。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Nodejs插件引入第三方动/静态链接库(Libtorch)的记录](https://blog.csdn.net/daydream13580130043/article/details/118359430)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值