月度归档:2016年03月

解决微信登录 “Scope 参数错误或没有Scope 权限” 问题

目前,微信,微博登录已经成为各个手机应用不可或缺的登录方式之一了,如果谁的app还没有添加这两种登录方式,那么您就落后于市场主流了。

然而,微信登录功能增加后,还是要经常维护的,比如每年需要进行公众号的年检,如果您没有及时年检,那么,微信登录就会出现很多问题。

笔者近期在调试app的时候,就发现,点击app的微信登录按钮,跳转到微信后,微信提示“Scope 参数错误或没有Scope 权限”,这让我感到莫名其妙啊。怎么可能scope参数错误呢,微信的Api中,用于登录的是SendAuthReq这个class,我很确定我设置了SendAuthReq的scope属性,并且是正确的。这么看来,真实的原因就是没有scope权限了。

多试验了几次,发现,有几次不会出现这个“Scope 参数错误或没有Scope 权限”错误,微信也会正确跳转回app,并且也可以获取code,然而,这时候调用微信的sns/oauth2/access_token API就会出现48001, api unauthorized错误。

最开始,我通过bing和google搜索了以上错误信息,结果,这个错误的根本原因多重多样。

  1. 2014年微信增加了“网页授权”,如果不开启这个选项,那么就会出现本错误。http://www.w-nn.cn/jiaocheng/423.html
  2. 还有人发现,scope参数在url中的位置不一样也会导致scope参数错误,http://my.oschina.net/u/202293/blog/387513。不过,笔者这里是iOS app用微信登录,所以可以排除这种可能
  3. 还有一些论坛中开发者求助,然后过了一会,求助的人自问自答道:“解决”。http://bbs.youzan.com/forum.php?mod=viewthread&tid=1113。 笔者看到这里感到,既然解决了,为什么不把原因和解决方案共享出来呢。
  4. mob.com的ShareSDK论坛也有人求助:http://bbs.mob.com/thread-20961-1-1.html,这个最后没有提到怎么解决的。
  5. 此外,还发现了http://tieba.baidu.com/p/4081677132,其中提到 乐动力 微信登录异常,原因就是微信公众号年审还没通过。而这里面所说的登录异常,就是“Scope 参数错误或没有Scope 权限”

我这次遇到的问题,根源就在于公众号没年审,所以微信登录被停掉了。我找运营部门的同事进行以下公众号年审就行了。

以前都及时年审了,所以没遇到这个问题,近年来,微信公众号申请的越来越多,这下子每个人要负责很多个微信号,这导致很容易就会有某个微信号维护不及时。

在UITabBar上识别长按(long press)操作

大家或许都知道,现在的智能手机都支持各种手势操作,如长按,单手指或者多手指滑动或点击,随着技术的发展,屏幕还可以识别按压的力度。

在iOS上,我们可以通过Tap/Pan/Pinch/Swipe/Rotate/LongPress Gesture Recognizer来识别各种手势,所以,在UITabBar上识别Long Press(长按)手势其实并不困难,只需要在tab bar上添加一个Long Press Gesture Recognizer就好了。

然而,以上的方案存在一个小小的瑕疵。iOS默认的tab bar,在你点击某一个tab bar button后,就会选中该button对应的item,而如果是tab bar controller的话,就会切换到对应的view controller。实际上,UITabBar在检测到用户按下以后,而不是按下然后拿起手指之后,就选中了对应的bar item,所以,tab bar在识别long press之前,就已经认为用户进行了一次tap。

实际上,更好的方案是,识别long press的话,就不要识别tap了。这就要求,我们需要修改tab bar识别tap的逻辑,即,用户必须touch down(按下)然后touch up(手指离开屏幕),才算一次,而非tab bar默认的行为,touch down就开始处理tap事件。

我采取的措施是,扩展UITabBar,在Tab Bar的view里添加一个overlay view,即这个view确保在Tab Bar的其他subviews的上面,由这个overlay view去识别Tap Gesture,当识别到Tap操作后,根据点击的坐标识别用户点击了哪一个tab bar item。

_overlayView = [[UIView alloc] init];
_overlayView.backgroundColor = [UIColor clearColor];
[self addSubview:_overlayView];
self.tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGesture:)];
[_overlayView addGestureRecognizer:self.overlayGestureRecognizer];
- (void)tapGesture:(UIPanGestureRecognizer*)gestureRecognizer{
    CGPoint point = [gestureRecognizer locationInView:self];
    switch (gestureRecognizer.state) {
        case UIGestureRecognizerStateEnded:
        {
            NSInteger touchUpItemIndex = [self barButtonItemIndexAtPoint:point];
            if (touchUpItemIndex != NSNotFound) {
                //touch up inside event
                UITabBarItem *item = [self.items objectAtIndex:touchUpItemIndex];
                //接下来,将selectedItem设置为item,并调用享用的delegate方法。
            }
        }
        break;
    }
}

 
以上代码的重点,就在于barButtonItemIndexAtPoint的实现。一个比较简单的实现就是,

CGFloat itemWidth = self.view.frame.size.width / self.items.count;
NSInteger index = point.x / itemWidth;

					

降低五险一金的真的是利国利民吗

3月17日,李克强总理在十二届全国人大四次会议记者会上答中外记者问 中,某央视记者提到,月薪8000元,到手实际收入不到5000元,3000元都缴纳五险一金了,企业和职工都希望能少缴;总理的回答是,让企业多减轻一些负担,让职工多拿一点现金。

我看到这个报道以后,第一反应就是,这种错误的让职工利益受害的言论,怎么会从央视记者口中说出,然后总理会说出企业减轻负担,职工多拿现金的话呢?

降低社保,职工究竟是受益还是受害呢?这一点我们要好好算算。以记者所说的8000月薪为例,按照北京的规则来计算,个人的缴费与企业的缴费如下。

税前工资 8000 现在的五险一金政策
养老 640   养老 1600
医疗 163   医疗 800
失业 16   失业 80
  工伤 24
  生育 64
公积金 960   公积金 960
个税 167
税后工资 6054
社保中进入个人账户的部分 医疗163 公积金960*2=1920
税后工资+社保+公积金 6054+163+1920 等于 8137

我们不难看到,税前工资8000,员工实际得到的收入和福利达到了8137,比税前收入还要高,其中最大的福利就是将近2000元的公积金了。这还没有算到达个人养老账户中的640元养老保险呢。

那么,如果按照现在的言论,降低五险一金比例,员工实际收入会如何变化呢。

税前工资 8000 五险一金比例减半
养老 320   养老 800
医疗 83   医疗 400
失业 8   失业 40
  工伤 12
  生育 32
公积金 480   公积金 480
个税 255.9
税后工资 6853
社保中进入个人账户的部分 医疗83 公积金480*2=960
税后工资+社保+公积金 6853+83+960 等于 7896

我们可以看到,如果五险一金比例减半的话,职工的税后工资变成了6853,与6054比多了将近800元钱,可是,你实际得到的总收益变成了7896元,与8137元相比,少了241元,而缴纳的个税也从167元变成了255元。

而企业减轻了多少负担呢?其实最大的支出节省就是这两个 1 养老保险少了800 2 医疗保险少了4000,总共减少了1200元。

所以,问题就变成,假设五险一金的比例变成减半,你愿意每个月的福利+到手工资从8137变成7896这种减半吗?

五险一金降低前 降低后 增幅
税后工资 6054 6853 +799
公积金 1920 960 -960
医疗个人账户 163 83 -80
个人所得税 167 255.9 +88.9

从以上表格可以看到,从8137到7896的代价,如果不考虑养老保险,可以近似为将960元的有提取条件的公积金变成为现金799元,在许多人眼里,或许这是可以接受的,甚至是非常划算的。然而,问题又来了。

上面的假设是五险一金整体比例减半,然而,这种假设可靠吗?可能性高吗?

我们来看看2015年已经进行了社保比例降低,据报道,2015年已经相继下调了失业、工伤和生育保险的费率。然而,我们再看看本文前面的表格,月薪8000元的,你缴纳的失业、工伤和生育分别为 职工(企业) 8(40), 0(12), 0(32)。这意味着,2015年的降低社保比例,完全是做个样子而已。占据缴费比例最高的养老保险和医疗保险,根本就没有动。

再考虑到目前大量报道都提到养老保险不可持续,缺口大,医保压力大,我们不难看出,国家下调养老和医疗的缴费的可能性非常小,那么,最有可能动的比例就是公积金了。

按照这个情况,我们的假设就调整为,公积金比例减半,其他比例不变,那么

税前工资 8000 五险不变, 一金减半
养老 640   养老 1600
医疗 163   医疗 800
失业 16   失业 80
  工伤 24
  生育 64
公积金 480   公积金 480
个税 215.1
税后工资 6486
社保中进入个人账户的部分 医疗163 公积金480*2=960
税后工资+社保+公积金 6486+163+960 等于 7609

你的税后到手工资从6054增加到了6486,增加了432元,但是,你损失的是960公积金以及多了48元个人所得税。企业节约了480元公积金,而国家仍然拿到了原来的养老和医疗的缴费。这样,作为职工的你还觉得划算么?

其实,要真的降低企业负担,增加职工到手收入,对于职工最好的政策,那就是公积金不设税前扣除的上限,企业负担的养老和医疗保险不要定20%和10%这么高的比例,那么,职工和企业就皆大欢喜了。可是,这样子,政府干么。

一个由于在非main queue进行了UIKit操作导致的奇怪的故障

今天调试app的时候,发现了一个奇怪的bug,当app需要pushViewController的时候,会出现一个奇怪的现象,就是push和pop的动画不会出现,即使animated参数都是YES。这个现象不是每次运行必然复现,而是运行10次,大概会有3到4次出现这个现象。

我经过试验,发现这个现象是从某天我开始编写某一个定制化的TabBar开始出现的,我将写这个控件之前的代码checkout出来,结果发现push/pop动画都一切正常,难道新的控件有什么bug。

经过一翻详细的检查,我发现其实导致这个bug的根本原因不是新的TabBar控件,而是我使用TabBar的代码存在问题,在background queue中进行了UIKit操作。

对于TabBar的每一个UITabBarItem,它的image和selectedImage都需要从网络下载,app在background queue下载image,然后resize到30×30,最后在main queue中赋值到tab bar item对应的属性。

问题就出在resize的步骤,我调用了UIImage的一个category的resizeImageToSize方法,这个方法会生成一个临时的UIImageView,将image view的size设置为目标image的size,从而实现resize。

所以,如果我要使用resizeImageToSize方法,那么我就必须在main queue中进行resize操作,而不能在background queue中进行resize操作。而这个方法不是我编写的,所以之前不知道这个方法会用到UIKit的东西,这导致我就无意中在background queue中进行了UIKit操作,而这次非法操作又没有导致app crash,所以我就没有第一时间想到可能是与UIKit和非main queue的问题。

发现了根本原因之后,我重写了resizeImageToSize方法,不再使用临时的UIImageView进行resize操作。

随后,我重新编译并运行app,多次操作后,push/pop动画的bug再也没有重现过,问题解决。

总结:如果你发现app突然变得很奇怪,有些时候,本来该有动画的,动画却没有出现,那么,几乎可以确定某一处代码在非main queue中进行了UIKit操作,而且这种操作不一定会导致crash。