新浪微博UWP版-实现‘分享功能’的艰难路
索引
在整个Team的共同努力下,在众多WPer的期待下,Weibo UWP版终于正式发布了。有关Weibo UWP版更多的信息请大家参考这篇博客。
我个人是今年年初才进公司的,之前没有做过正规大型的UWP项目,只是平时出于个人喜爱做了一些跟Windows10相关的小东西。幸亏组里的其他几位Colleagues有一些经验,给我帮助了不少。大概在第一版提交测试之后,老板带领我们开了一个小会,规划了一下下一版本应该新增的几个功能,主要包括:夜间模式、搜索以及分享这三个。我被指定主要负责完成‘分享’这个功能,大概就是能将外部的‘照片’、‘链接’以及‘文本’通过系统分享渠道分享到微博中。当时感觉功能尤其简单,花一两天就能搞定,最终却发现困难重重。
‘分享’这个功能要求微博APP作为数据的接收方,能够接收外部APP传过来的数据:
如上图所示,用户可以分享‘图片’、‘URL’以及文本等内容到微博中。注意这里的微博APP是作为‘数据接收方(Receiver)’,这次主要讨论的是这种情况。下图显示的是APP作为‘数据发送方(Sender)’的情况:
以上两种情况是对立的,前者接收数据,而后者发送数据。
搞懂原理之后,其实实现起来非常简单。本质上就是一个APP唤起另外一个APP(关于APP之间的数据交换和唤醒请参考这篇博客),我们只需要在APP接收方(即微博UWP)中的App这个Class中重写OnShareTargetActivated(ShareTargetActivatedEventArgs args)这个方法即可,然后在该方法中解析数据(如果需要),最后显示最终的分享界面。
现在你可能会说,如此简单,为什么会出现问题呢?是的,一开始我也觉得非常简单,迅速地将代码写完了,在OnShareTargetActivated方法中大概的逻辑是这样的(以分享图片为例):
就在我摁下F5心想大功告成的时候,灾难出现了:每次不管是弹出‘登录界面’还是‘分享界面’时,主APP总会Crash。而且会报“you are accessing interface provided by another thread”的ErrorMsg。!我没有跨线程访问控件啊。
之后我连续Google了两天,除了StackOverflow上面有一篇跟我遇到相似的问题之外(关键还没人回复),其余什么思路也找不到。最后实在没有办法,抱着试一试的心态咨询了一下USA那边负责App2App方面的同事:
--------------------------Mail----------------------------
----------------------------------------------------------
发完邮件后我继续在网上找答案,仍然没有找到解决方案。就在我对这个bug迷茫不知所措的时候,有人给我回复邮件了:
--------------------------Mail----------------------------
----------------------------------------------------------
大概的意思是MSDN上的描述有错误,他们计划更正,但是并没有回复我为什么会报那个错误。之后我继续询问:
--------------------------Mail---------------------------
---------------------------------------------------------
这个时候我已经开始怀疑同一个App中存在了两个UI Thread的可能。不过多久,对方给我回复,证实了我的怀疑是对的:
--------------------------Mail---------------------------
---------------------------------------------------------
我的怀疑得到证实之后,心中大喜,终于知道原因了。但是我马上一想:即使同时存在两个UI线程,各自单独实例化自己的Pages、Controls等UI资源,为什么会报错呢?这时候我就开始怀疑之前别人写过的Pages、Controls内部代码是不是有问题。
由于刚接触项目不久,还不是完全清楚整个项目代码,尤其是那些已经稳定了几乎不会变的部分。我挨个打开‘登录界面’和‘分享界面’中涉及到的控件文件,挨个查看,最终发现了根本原因:
几乎大部分控件使用了单例模式。
是的,你没有听错,大部分控件都包含Static Instance这个静态属性,所有后台代码都是通过该静态属性去使用控件的。
知道原因了,下一步就是开始解决问题。那么怎样去解决呢?我刚开始打算将涉及到的控件(登录页面、分享页面使用了多种控件)、页面中的单例模式全部去掉,即使用正常的初始化。后来发现由于依赖太强,改完一个之后所有一连串的Class全部要改,这样波及到的文件太多太多。我不太敢这样下手,毕竟改动太大,可能会影响原来代码的稳定性。
最后取了一个折中的办法,将依赖性不高的文件改了,依赖性太高的Control我干脆复制了一份代码,另外取了一个相似的名称(万幸这样的Class最终发现只有三个)。
最终问题顺利解决了。分享时可以正常弹出登录界面以及分享界面。下面传一张分享界面的图(分享图片为例,均来自模拟器的截图):
以上是我解决一个问题的完整过程,从发现问题,到寻求帮助到最终问题的完美解决。没有下载微博UWP版的童鞋可以去试一下了! 很多功能都会在下一版中加进去,包括这篇文章中说到的‘分享’。
注:分享、搜索等功能如果不出意外的话,下一版本会发布。