社交化分享组件踩坑

issue:微信登录失败

问题是这样的,项目里的社交化分享是基于 UMShare 封装成的一个 ShareLib module,为了让这个 module 对调用者说更透明,我将 WXEntryActivity申明App module 移动到了 ShareLib module里, AndroidMainifest.xml 中关于 WXEntryActivity申明如下:

ShareLibrary的 AndroidMainifest 里的申明

同时把 wxapi 目录(包含 WXEntryActivity.java 也一并转移,根目录下的 wxapi 目录如图:

根目录下的wxapi目录

App module 确实清爽了不少。但是,这么做会引发怎样的问题呢?

目前发现的问题

  • 用户点击微信登录总是失败,无法正常跳转到微信授权页面
  • 用户无法使用微信分享
  • 以上两种情况都会抛出 NameNotFoundException

冷静分析

友盟的文档

配置Android Mainifest XML,文档里明确指出是需要在 AndroidMainifest 里申明 WXEntryActivity, 并在根目录下新建一个 wxapi 包,然后将 WXEntryActivity 放在里面。但说如果把这些东西放到 module项目里会如何,友盟并没有说,emmmm…

遇事不觉 Debug

进入 UMShare SDK 的源码里探索了一番后,将错误锁定在了 checkWxBySelf 这个静态方法上,该方法声明如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public static String checkWxBySelf(Context context) {
// 获取包名
String pkName = context.getPackageName();
// 获取类名
String classPath = pkName + ".wxapi.WXEntryActivity";
PackageInfo packageInfo = null;
PackageManager packageManager = null;
try {
packageManager = context.getPackageManager();
packageInfo = packageManager.getPackageInfo(pkName, 64);
} catch (NameNotFoundException var8) {
var8.printStackTrace();
}
String result = getSignatureDigest(packageInfo);
try {
// 1.通过全名加载 WXEntryActivity 类
Class<?> clz = Class.forName(classPath);
if(clz == null) {
return "请检查微信后台注册签名:" + result.toLowerCase() + "\n" + "包名:" + pkName + "\n" + "没有配置微信回调activity或配置不正确";
}
if(Config.isUmengWx.booleanValue()) {
if(clz.getSuperclass() == null) {
return "WXEntryActivity配置不正确,您使用的是精简版,请使WXEntryActivity继承com.umeng.weixin.callback.WXCallbackActivity";
}
if(!clz.getSuperclass().toString().contains("com.umeng.weixin")) {
return "WXEntryActivity配置不正确,您使用的是精简版,请使WXEntryActivity继承com.umeng.weixin.callback.WXCallbackActivity";
}
} else {
if(clz.getSuperclass() == null) {
return "WXEntryActivity配置不正确,您使用的是完整版,请使WXEntryActivity继承com.umeng.socialize.weixin.view.WXCallbackActivity";
}
if(!clz.getSuperclass().toString().contains("com.umeng.socialize")) {
return "WXEntryActivity配置不正确,您使用的是完整版,请使WXEntryActivity继承com.umeng.socialize.weixin.view.WXCallbackActivity";
}
}
} catch (ClassNotFoundException var9) {
var9.printStackTrace();
return "请检查微信后台注册签名:" + result.toLowerCase() + "\n" + "包名:" + pkName + "\n" + "没有配置微信回调activity或配置不正确";
}
try {
ComponentName componentName = new ComponentName(context.getPackageName(), classPath);
// 2.根据指定的组件,获取 ActivityInfo 信息
packageManager.getActivityInfo(componentName, 0);
return "请检查微信后台注册签名:" + result.toLowerCase() + "\n" + "包名:" + pkName + "\n" + "Activity微信配置正确";
} catch (NameNotFoundException var7) {
var7.printStackTrace();
return "请检查微信后台注册签名:" + result.toLowerCase() + "\n" + "包名:" + pkName + "\n" + "没有配置微信回调activity没有在Manifest中配置";
}
}

注释里已经写了两个可能抛出异常的地方,和 packageName 都有关系,也就是说我们能否正确获取 packageName 直接影响到能否正常使用 UMShare SDK 的功能!很显然,我们的 App Module 里并没有对应的 WXEntryActivity,所以执行到注释1的时候就会抛出异常了!

补充

如果,我在 App module 里加上 wxapi 目录就 OK 了嘛?

答案是no!还是会报错,只不过这次是在注释2抛出异常。

又报错,这次明明加上了 wxapi 目录,已经可以找到 WXEntryActivity 了,为毛还是报错勒,emmm,再来冷静分析下吧。

多个 AndroidMainifest 的合并

关于多个 AndroidMainifest 的合并问题,可以去Android 官网补补课。

因为我们的项目有多个 module,每个 module 都有自己的 AndroidMainifest,而最终,这些文件会被合并为一个文件。

还是看看 Merged AndroidMainifest 吧

App module 下的 merge 后的 AndroidMainifest 模样

1
2
3
4
5
6
<activity
android:name="info.hellovass.sharelib.wxapi.WXEntryActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="true"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.Translucent.NoTitleBar"/>

ShareLib module 下的 merge 后的 AndroidMainifest 模样:

1
2
3
4
5
6
<activity
android:name="info.hellovass.sharelib.wxapi.WXEntryActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="true"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.Translucent.NoTitleBar"/>

分析

因为我们并没有在 App module 下的 AndroidMainifest 对 WXEntryActivity 做任何申明,所以,merge 时会合并 ShareLib module 里的申明,于是,就变成了上面这样子。看到这里,我想事情也明了了,因为这种情况,ShareLib module 的包名和 App module 的包名是不一致的。简单来说,WXEntryActivity 并未注册到 AndroidMainifest 中,所以会在 packageManager.getActivityInfo(component, 0) 出抛出异常。