我的GitHub
0%

角色权限判断,这应该是大部分应用都有的功能,那么如何进行权限判断?

这里说下我们用的思路,可能会比较low,各位看官别笑。

打个比方,我现在有A,B,C,D四个功能。要对某个账户是否具有这些功能权限做判断。
我们有个list,里面存放着这个账户所有的权限。(list从哪来?当然是后台请求回来啊!)
A功能对应的权限是=>0,以此类推B=>1,C=>2,D=>3这样子。

那么如果我有一个账号拥有所有权限,list就是【0,1,2,3】,如果没有B权限就是【0,2,3,4】这样子,相信大家都应该明白我要表达的意思了。

那么要判断是否拥有某个权限,这时候肯定就会说,遍历一下list不就知道了?那如果权限比较多呢?而且你不觉得这样更low么=。=
所以这个时候,我们可以使用位运算打成这个目的:

先说我们用来判断的方法:

1
2
3
4
//判断是否存在权限,permission是所有权限展示中的某个权限,只有一个&,不是两个,别搞错了
hasPermission(permission) {
return permission & GlobalValue.authValue
}

再定义一个包含了所有权限的声明

1
2
3
4
5
6
7
8
//所有权限列表展示
export let Permission = {
A: Math.pow(2, 0), //A功能
B: Math.pow(2, 1), //B功能
C: Math.pow(2, 2), //C功能
D: Math.pow(2, 3), //D功能
...
}

在我们和后台请求拿到某个角色所包含的list的时候,对list做如下操作

阅读全文 »

背景:rn好多前端或者安卓转的旁友对iOS的打包不太熟悉,所以写个图文教程版,目前我对应的版本是0.4+版本和0.5+版本(反正我也是随便写的,参考为主)
PS:账号的申请还有各种证书的申请我就不多提了,自己百度查下。。
###1.打开项目中iOS文件夹,新建一个名为bundle的文件夹
如图
###2.打开终端,cd到整个项目根目录
如图中的catten目录
###3.输入命令行,版本不同命令不一样哟,注意看
区分标准是你是否存在index.ios.js,存在肯定是老版本,用下面这个命令

1
react-native bundle --entry-file index.ios.js --bundle-output ./ios/bundle/index.ios.jsbundle --platform ios --assets-dest ./ios/bundle --dev false

如果你是index.js,那就是新版本啦,用下面这个命令

1
react-native bundle --entry-file index.js --bundle-output ./ios/bundle/index.jsbundle --platform ios --assets-dest ./ios/bundle --dev false

###4.把上面命令输入终端并按下回车
等待时间可能要一会
如图
###4.补,差点漏了一点注意事项
可能有的旁友项目中有webview承载html页面
这时候你命令行打出来的包可能就要注意一下了
如下图,我这是bundle文件夹下assets文件夹里的资源文件夹
如图
实际上我这个html有多少文件呢
实际这么多
你会发现少了东西,这时候怎么办,很简单,去你项目中把相关缺少的文件复制到assets里就行

###5.打开Xcode项目
直接拖过去
直接拖过去
记得选下面这个哟,蓝色的物理文件夹
选下面这个
选完长这样
选完长这样
###6.这时候打开appdelegate(我改了东西,里面代码是一样的,不过我的位置不一样,你们看下就知道了)
把jsCodeLocation的来源换成你打的包的来源(其他人怎么打包、调试、开发我不清楚,反正我是这么做的,而且已经上架两个项目了,我确定是可用的)
js的地址

还是老样子,index.ios.js填

1
jsCodeLocation = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"index.ios.jsbundle" ofType:nil]];

index.js填

1
jsCodeLocation = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"index.jsbundle" ofType:nil]];
阅读全文 »

其实iPhone的指纹识别有很多教程,但其实有两套策略,而且好多都只写了一套,而且有的你会发现,错误码压根就试不出来啊,还以为苹果给的错误码都是瞎扯淡的。

首先,需要导入苹果的安全策略库LocalAuthentication。
导入库
这个库提供了指纹识别这一安全策略库公开发者们使用。
对于开发者来说,只需要调用几个很简单的方法便可以进行指纹识别了。至于是如何识别,这些苹果并没有公开,开发者只能获取成功或失败状态以及message。
###一.判断设备是否支持指纹识别

1
2
3
4
5
LAContext *context = [[LAContext alloc] init];
NSError *error = nil;

// 判断设置是否支持指纹识别(iPhone5s+、iOS8+支持)
BOOL support = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];

###但是注意了,这里的support如果为NO并不代表设备就不支持指纹识别了。
因为当出现:
1.设备支持TouchID但TouchId被锁时:LAErrorTouchIDLockout
2.设备支持TouchID但没有设置密码:LAErrorPasscodeNotSet(但实际上会走LAErrorTouchIDNotEnrolled)
3.设备支持TouchID,设置了密码,但没有设置TouchID:LAErrorTouchIDNotEnrolled
这几种情况统统都会报Support为NO

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
if (support) {
return AllRight;
}else{
switch (error.code) {
// 没有设置指纹(没有设置密码也会走到这),但是支持指纹识别
case LAErrorTouchIDNotEnrolled:{
return TouchOK;
}
break;
// 理论上是没有设置密码,至今没有尝试出什么情况下走这个,希望有试出来场景的兄弟告知一下我
case LAErrorPasscodeNotSet:{
return TouchOK;
}
break;
// 在使用touchID的场景中,错误太多次(根据策略不同为5次到6次)而导致touchID被锁不可用
case LAErrorTouchIDLockout:{
NSLog(@"密码封锁");
return TouchOK;
}
// 设备不支持指纹识别
default:{
return AllError;
}
break;
}
}
}

###二.指纹识别如何唤起(其实是安全策略的唤起)
其实整个LocalAuthentication库是一个安全策略库,我们所说的指纹只是安全策略的一种,主要为生物技术的使用。这种策略有非常多的种类,现在常用的指纹,iPhone X的face ID,没准以后还会有虹膜等更多的安全策略出现。

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

[authenticationContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:@"通过Home键验证已有手机指纹" reply:^(BOOL success, NSError * _Nullable error) {
// 指纹识别错误调用分为以下情况,
// 点击取消按钮 : domain = com.apple.LocalAuthentication code = -2
// 点击输入密码按钮 : domain = com.apple.LocalAuthentication code = -3
// 输入密码重新进入指纹系统 : domain = com.apple.LocalAuthentication code = -8
// 指纹三次错误 : domain = com.apple.LocalAuthentication code = -1
// 指纹验证成功 : error = nil
if (error) {
switch (error.code) {
// 指纹识别3次失败进入这里
case LAErrorAuthenticationFailed:
NSLog(@"验证失败");
break;
// 指纹识别时,点击取消
case LAErrorUserCancel:
NSLog(@"点击取消按钮");
break;
// 指纹识别时,点击输入密码按钮
case LAErrorUserFallback:
NSLog(@"点击输入密码按钮");
break;
// 没有在设备上设置密码(我没试出来这一项,有试出来的兄弟评论告诉我一下)
case LAErrorPasscodeNotSet:
NSLog(@"没有在设备上设置密码");
break;
// 设备上TouchID不可用,例如未打开(我没试出来这一项,有试出来的兄弟评论告诉我一下)
case LAErrorTouchIDNotAvailable:
NSLog(@"设备不支持TouchID");
break;
// 没有设置TouchID
case LAErrorTouchIDNotEnrolled:
NSLog(@"设备没有注册TouchID");
break;
// 设备TouchID被锁,且只会在iOS9以上设备出现
case LAErrorTouchIDLockout:
NSLog(@"TouchID被锁");
break;
// 由于不可抗拒力,应用进入后台(其实很简单,你写两个测试demo,在一个启动指纹时开启另一个项目,你的指纹项目就会因为不可抗力进入后台,这时候就会走到这)
case LAErrorSystemCancel:
NSLog(@"由于系统阻止,转入后台");
break;
default:
// 直接写失败吧,也没别的原因了,进入这里都很难了
break;
}
return ;
}
else{
NSLog(@"识别成功");
}
}];

一般用上面写的这段代码就行了
接下来咱们说说策略

1
2
3
4
5
6
/// @param policy 策略
/// @param localizedReason 提示语
/// @param reply Reply block 回调的代码块
[myContext evaluatePolicy:<#(LAPolicy)#> localizedReason:<#(nonnull NSString *)#> reply:^(BOOL success, NSError * _Nullable error) {

}];

咱们来谈谈policy,这玩意有两个枚举值

阅读全文 »

其实集成个推的途中一直很坎坷,不知道到底他们的推送是个什么东西,透传,普通推送,什么情况才是正常的。这里写一下,没有代码,只是阐述正确情况下推送通道应该产生的效果。

ios的消息是分两部分的 一部分是走apn的通知栏消息 另一部分是走个推通道的透传消息 这两部分是服务端推送代码里面集成个推的后端同事会设定好的 分别是两个不同的方法 如果消息下发的时候 你客户端是在后台的(也就是客户端是离线)那么会收到apn的通知 透传消息就进离线了 只有你下次在线的时候 (也就是下次应用到前台的时候)才会下发下来 如果下发的时候应用是在前台的 那这样的话客户端就直接收到透传消息了

应用退到后台,或者杀进程,cid离线才会推送苹果apn,客户端才会收到apn通知栏提醒的,cid在线直接走个推通道,客户端收到个推透传消息,如果需要展示通知栏需要自己客户端定义处理解析个推透传消息

阅读全文 »

背景:公司的老项目,使用的是uiwebview,我也没用过,第一次做混合开发,所以想直接使用wkwebview去替换当前的uiwebview,毕竟性能上提升了4倍,还有很多乱七八糟的优化等,废话不多说。

###1.首先wkwebview有三个代理方法WKUIDelegate,WKScriptMessageHandler,WKNavigationDelegate

###2.wkwebview创建的时候可以写配置
有一个属性的集合,叫WKWebViewConfiguration
其中还有一些首选项的配置WKPreferences
例如我是这么创建的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//    wkwebview属性的集合
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc]init];
// webview一些首选项的配置
WKPreferences *preferences = [[WKPreferences alloc]init];
// 在没有用户交互的情况下,是否允许js打开窗口,macOS默认是yes,iOS默认是no
preferences.javaScriptCanOpenWindowsAutomatically = YES;
// webview的最小字体大小
// preferences.minimumFontSize = 40.0;

configuration.preferences = preferences;

self.webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:configuration];
self.webView.UIDelegate = self;
self.webView.navigationDelegate = self;
[self.view addSubview:self.webView];

###3.加载网页,本地加载和加载服务器网页
######1.加载本地网页
将html与css和js拖进项目,使用蓝色物理文件夹放入。
加载本地网页,使用

1
[self.webView loadFileURL:htmlPathUrl allowingReadAccessToURL:folderPathUrl];

其中htmlPathUrl代表html的路径
其中folderPathUrl代表存放js与css的路径
只有这样才能加载完整的网页,否则你可能加载不出css样式和js方法。
例如:

1
2
3
4
5
6
7
8
9
10
#pragma mark 加载url展示页面
//加载本地网页
-(void)loadUrl{
NSString *folderPath = [[NSBundle mainBundle] pathForResource:@"sdk" ofType:@""];
NSURL *folderPathUrl = [NSURL fileURLWithPath:folderPath];

NSString *htmlPath = [folderPath stringByAppendingString:@"/h5/index.html"];
NSURL *htmlPathUrl = [NSURL fileURLWithPath:htmlPath];
[self.webView loadFileURL:htmlPathUrl allowingReadAccessToURL:folderPathUrl];
}

当然,如果网页有ajax请求,注意跨域问题。试试jsonp。这里就提一下,略过。

######2.加载服务器网页
这就没什么好说的了。。直接加载就行。
例如:

阅读全文 »

其实就是用workspace把两个项目连起来
凉白开记录了,懒得写了。。
地址:http://www.jianshu.com/p/6c9b380cfe5c?utm_source=desktop&utm_medium=timeline
如果修改了文件位置或者啥的,报头文件找不到,去示例代码工程把

49F27CAE-95C4-4F32-80EC-543ADFD05B49.png
把sdk的link删掉再加上,重新运行就好了

//—————以下是凉白开总结的——————//

自从上次写完SDK并接入别人的项目中之后就一直没怎么管过这东西了,昨天一人突然问我调试SDK怎么弄,我说不能。(结果今天啪啪啪自己打脸了) 恩他解决了一个SDK不能调试的一个超级大问题,征得同意后我来记录一下,自己记录一下其次文后并附上他的简书地址。

1.新建workspace。

img

新建workspace

*2.新建文件夹,将*workspace,demo以及SDK**放入文件夹中。****

img

新建文件夹及放入

阅读全文 »

前人挖坑后人填。。。。
阐述一下背景:
 App更新迭代,需要跟后台做一个版本控制更新的开关。正常来说应该是将xcode的version与App Store的version对应,并通过该值判断开关是否打开。
 但是问题来了。。上一位iOS工程师一直是使用的build进行版本控制,本地xocde的version比App Store的version高出不少。
 先说一说Version。分为xcode的version和App Store的version。理论上应该两者一致。方便维护。

###xcode的version
可以通过

1
2
//  获得version号
NSString *versionCode =[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];

获取,获取的是info.plist文件中的
335E8913-16AA-4B95-B4CB-63B50AEF28F6.png

###App Store的version
则是通过调取接口:
https://itunes.apple.com/lookup?id=你的app的id号;
调用方式:post
返回结果:

1
2
3
NSArray *array = responseObject[@"results"];
NSDictionary *dict = [array lastObject];
NSLog(@"当前版本为:%@", dict[@"version"]);

代码如下:

1
2
3
4
5
6
7
8
9
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:@"https://itunes.apple.com/lookup?id=414478124" parameters:nil success:^(AFHTTPRequestOperation * _Nonnull operation, id _Nonnull responseObject) {
NSArray *array = responseObject[@"results"];
NSDictionary *dict = [array lastObject];
NSLog(@"当前版本为:%@", dict[@"version"]);
} failure:^(AFHTTPRequestOperation * _Nullable operation, NSError * _Nonnull error) {
NSLog @"请求失败";
}];
}

正常来说都是对外暴露的版本,xcode与App Store的版本理应一致。方便维护。

###build:
开发内部测试版本号,写多少都行,内部开发测试用的,写多少都行,最好是不要对外暴露。因为每次打包都需要往上+,所以用于版本控制效果不好。

阅读全文 »

#1.第三方App跳转
这是很常见的问题,第三方app跳转到本app去做一些业务操作。
但是这时候会发现,你跳进来,是黑色的,没有界面,没想到吧23333
其实这在前面说过,RN的想法很独特,是一个ctrl上放了无数个view,不停的更改view来渲染,而rn的首页view,则是在appdelegate的初始化方法里去添加的。跳转进来的处理方法里如果你不写,就不会有view添加进来。
所以这时候有两种方法来完成这个view的添加操作:
####A.在第三方跳转进来的方法里做视图加载操作,但是这会遇到一个问题。假使你使用了RN的启动页,你会发现每次跳转进来都会开启启动页。这对用户的体验明显是很不好的。
####B.自己创建一个UIViewCtrl,并作为根视图放进window中,在这个UIViewCtrl中做视图加载操作。这样跳转进来加载根视图的时候就会把这个RN的View给加载上去。而且根据生命周期场景复现的原则,不会再有加载第二次第三次的情况。

如图

Appdelegate.m

RootViewCtrl.m

另外,如果要跳到某一页面做某一操作,又不想重复跳,可以采用以下方式移除

第三方跳转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#pragma mark --第三方跳转进入这里(新)
-(BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
// NSLog(@"url ====%@",url);
thirdViewController *vc = [thirdViewController sharedthirdViewController];
vc.url = url;

UIViewController *topViewCtrl = self.nav.topViewController;
if ([topViewCtrl isKindOfClass:[thirdViewController class]]) { //判断是否在最顶层
[vc thirdSign];
}else{
[self.nav pushViewController:vc animated:YES];
[vc thirdSign];
}
return YES;
}

#2.应用升级苹果商店跳转
这个就很简单了啊,直接link:app在苹果商店的地址就行,至于怎么找app在苹果商店的地址,谷歌一下或百度一下都有。
#3.启动屏设置
采用了RN的启动页,你需要把原生的启动页稍作更改。把这个勾去掉

把这里改一下

#3.按钮点击封装防止二次点击
是不是有时候控件响应较慢,点击两次还以为没反应,结果却运行两次操作,感觉比较烦人。
这里贴出一个大佬给的方式,其实是采用定时器操作,只要有点击操作,做出事件处理,并开启定时器,在定时器时间内屏蔽其他的点击操作。

阅读全文 »

git:https://github.com/react-community/react-navigation/issues/1493
来,下猛药:
首先找到文件:src/views/ScenesReducer.js
然后用下面的代码:
  let k = null;
  let v = null;
  staleScenes.forEach(scene => {
  let {key} = scene;
  k = key;
  v = scene;
  });
  newStaleScenes = k && v ? new Map([[k, v]]) : new Map();
  newStaleScenes.forEach(mergeScene);
替换:staleScenes.forEach(mergeScene);
保存编译,就只有返回某页的动画了

转自http://www.cnblogs.com/lc901221/p/7543094.html
我就是那个贴了帖子看不懂答案的傻逼,。。

另外:
transitionConfig : () => ({
transitionSpec: {
duration: 0,
timing: Animated.timing,
easing: Easing.step0,
},
}),
去掉动画效果

2018-2-23 更新
以上解决方案适用于1.0.0beta版
升级到React-navigation 1.1.1版本后可直接通过key去回退指定版本。
至于怎么取key=>可以在跳转时缓存页面对应key值,通过页面名去获取缓存的key值跳转。
注意源码中当页面层级index为0时(首页)不会back。这一块应该是有想法的,但在特定情况下会有bug,因为我们项目就遇到了–但我暂时无法用语言总结出出现的场景。

无星的RN学习之旅(一)-环境安装以及新建项目
无星的RN学习之旅(二)-RN与原生的通信
无星的RN学习之旅(三)-bridge is not set.
无星的RN学习之旅(四)——通信、持久化存储、xcode打包
无星的RN学习之旅(六)-第三方App跳转,苹果商店跳转,loading框

阅读全文 »

废话不多说,直接上问题:
1.如何拼接请求头?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//申明返回的结果是json类型

manager.responseSerializer = [AFJSONResponseSerializer serializer];

//申明请求的数据是json类型

manager.requestSerializer=[AFJSONRequestSerializer serializer];

// /如果报接受类型不一致请替换一致text/html或别的

[manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[manager.requestSerializer setValue:value forHTTPHeaderField:key];
[manager.requestSerializer setValue: value forHTTPHeaderField:key];
[manager.requestSerializer setValue: value forHTTPHeaderField:key];


2.如何返回参数在调用的同一方法中?

block,参数带有block去实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
__block NSString *longitude; // __block,静态变量
[self.manager POST:URL parameters:params success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {

NSDictionary *locDictionary = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableLeaves error:nil];
longitude = [locDictionary objectForKey:@"lon"]; // 纠正后经度

if (finishBlock)
{
finishBlock(longitude, nil);
}

} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"%@", error);
if (finishBlock)
{
finishBlock(nil, error);
}
}];
阅读全文 »