// 定义 const ApiBridge = { msgQueue: [], callbackCache: [], callbackId: 0, processingMsg: false, isReady: false, isNotifyReady: false }; ApiBridge.callNative = function(clz, method, args, callback) { var msgJson = {}; msgJson.clz = clz; msgJson.method = method; if (args != undefined) msgJson.args = args; return prompt(JSON.stringify(msgJson)); }; // 调用 setTimeout(() => { this.$ApiBridge.callNative("KCApiTSLModule", "notifyF", { action: 'closePage', param: {} }); }); 以上代码经测试不能很好的兼容ios,下面的代码可以:
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 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
; (function(window) { if (window.WebViewJSBridge) return; window.WebViewJSBridge = {}; console.log("--- kerkee init begin---"); var browser = { versions: function() { var u = navigator.userAgent, app = navigator.appVersion; return { trident: u.indexOf('Trident') > -1, //IE presto: u.indexOf('Presto') > -1, //opera webKit: u.indexOf('AppleWebKit') > -1, //apple&google kernel gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //firfox mobile: !!u.match(/AppleWebKit.*Mobile.*/), //is Mobile ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //is ios android: u.indexOf('Android') > -1 || u.indexOf('Adr') > -1, //android iPhone: u.indexOf('iPhone') > -1, //iPhone or QQHD iPad: u.indexOf('iPad') > -1, //iPad iPod: u.indexOf('iPod') > -1, //iPod webApp: u.indexOf('Safari') == -1, //is webapp,no header and footer weixin: u.indexOf('MicroMessenger') > -1, //is wechat qq: u.match(/\sQQ/i) == " qq", //is qq, wxwork: u.indexOf('wxwork') > -1 //is wechat }; }(), language: (navigator.browserLanguage || navigator.language).toLowerCase() } var global = this || window; var ApiBridge = { msgQueue: [], callbackCache: [], callbackId: 0, processingMsg: false, isReady: false, isNotifyReady: false }; ApiBridge.create = function() { ApiBridge.bridgeIframe = document.createElement("iframe"); ApiBridge.bridgeIframe.style.display = 'none'; document.documentElement.appendChild(ApiBridge.bridgeIframe); }; ApiBridge.prepareProcessingMessages = function() { ApiBridge.processingMsg = true; }; ApiBridge.fetchMessages = function() { if (ApiBridge.msgQueue.length > 0) { var messages = JSON.stringify(ApiBridge.msgQueue); ApiBridge.msgQueue.length = 0; return messages; } ApiBridge.processingMsg = false; return ''; }; ApiBridge.callNative = function(clz, method, args, callback) { var msgJson = {}; msgJson.clz = clz; msgJson.method = method; if (args != undefined) msgJson.args = args; if (callback) { var callbackId = ApiBridge.getCallbackId(); ApiBridge.callbackCache[callbackId] = callback; if (msgJson.args) { msgJson.args.callbackId = callbackId.toString(); } else { msgJson.args = { "callbackId": callbackId.toString() }; } } if (browser.versions.wxwork || browser.versions.weixin) { return; } if (browser.versions.ios) { if (ApiBridge.bridgeIframe == undefined) { ApiBridge.create(); } // var msgJson = {"clz": clz, "method": method, "args": args}; ApiBridge.msgQueue.push(msgJson); if (!ApiBridge.processingMsg) ApiBridge.bridgeIframe.src = "kcnative://go"; } else if (browser.versions.android) { // android return prompt(JSON.stringify(msgJson)); } }; ApiBridge.showVersion = function() { return browser.versions; } ApiBridge.log = function(msg) { ApiBridge.callNative("ApiBridge", "JSLog", { "msg": msg }); } ApiBridge.getCallbackId = function() { return ApiBridge.callbackId++; } ApiBridge.onCallback = function(callbackId, obj) { if (ApiBridge.callbackCache[callbackId]) { ApiBridge.callbackCache[callbackId](obj); } } ApiBridge.onBridgeInitComplete = function(callback) { ApiBridge.callNative("ApiBridge", "onBridgeInitComplete", {}, callback); } ApiBridge.onNativeInitComplete = function(callback) { ApiBridge.isReady = true; if (callback) { callback(); ApiBridge.isNotifyReady = true; } } ApiBridge.compile = function(aIdentity, aJS) { var value; var error; try { value = eval(aJS); } catch (e) { var err = {}; err.name = e.name; err.message = e.message; err.number = e.number & 0xFFFF; error = err; } ApiBridge.callNative("ApiBridge", "compile", { "identity": aIdentity, "returnValue": value, "error": error }); } var _Configs = { isOpenJSLog: false, isOpenNativeXHR: false }; var kerkee = {}; /***************************************** * 事件监听 *****************************************/ kerkee.Event = {}; // kerkee.Event.LOADED = "loaded"; // kerkee.Event.LOAD_ERROR = "load_error"; // kerkee.Event.LOAD_PROGRESS = "load_progress"; kerkee.addEventListener = function(event, callback) { ApiBridge.callNative("event", "addEventListener", { "event": event }, callback); } /* Scroll to the bottom of the page when the callback function and the threshold setting */ //callback:Return to the page in webview upper vertex Y value kerkee.registerHitPageBottomListener = function(callback, threshold) { ApiBridge.callNative("ApiBridge", "setHitPageBottomThreshold", { "threshold": threshold }); kerkee.onHitPageBottom = callback; }; kerkee.registerScrollListener = function(callback) { ApiBridge.callNative("ApiBridge", "setPageScroll", { "isScrollOn": true }); kerkee.onPageScroll = callback; }; kerkee.notifyF = function(aString) { ApiBridge.callNative("KCApiTSLModule", "notifyF", aString); }; global.KCApiTSLModule = kerkee; /***************************************** * 接口 *****************************************/ kerkee.testJSBrige = function(aString) { ApiBridge.callNative("jsBridgeClient", "testJSBrige", { "info": aString }); }; kerkee.openJSLog = function() { _Configs.isOpenJSLog = true; } kerkee.closeJSLog = function() { _Configs.isOpenJSLog = false; } kerkee.commonApi = function(aString, callback) { ApiBridge.callNative("jsBridgeClient", "commonApi", { "info": aString }, callback); } kerkee.onDeviceReady = function(handler) { ApiBridge.onDeviceReady = handler; if (ApiBridge.isReady && !ApiBridge.isNotifyReady && handler) { handler(); ApiBridge.isNotifyReady = true; } }; kerkee.invoke = function(clz, method, args, callback) { if (callback) { ApiBridge.callNative(clz, method, args, callback); } else { ApiBridge.callNative(clz, method, args); } }; kerkee.onSetImage = function(srcSuffix, desUri) { var obj = document.querySelectorAll('img[src$="' + srcSuffix + '"]'); for (var i = 0; i < obj.length; ++i) { obj[i].src = desUri; } }; /* * var windowOpen = function (url) { ApiBridge.callNative("JavascriptAPIInterceptor", "windowOpen", { "url" : url }); }; */ global.ApiBridge = ApiBridge; global.kerkee = kerkee; global.jsBridgeClient = kerkee; kerkee.register = function(_window) { _window.ApiBridge = window.ApiBridge; _window.kerkee = window.kerkee; _window.console.log = window.console.log; _window.open = window.open; }; ApiBridge.onBridgeInitComplete(function(aConfigs) { if (aConfigs) { if (aConfigs.hasOwnProperty('isOpenJSLog')) { _Configs.isOpenJSLog = aConfigs.isOpenJSLog; } if (aConfigs.hasOwnProperty('isOpenNativeXHR')) { _Configs.isOpenNativeXHR = aConfigs.isOpenNativeXHR; } } if (_Configs.isOpenJSLog) { //global.console.log = ApiBridge.log; } ApiBridge.onNativeInitComplete(ApiBridge.onDeviceReady); }); })(window); |
View Details
1.配合使用调用app原生的方法(h5页面不需要回调和数据) 实例1
1 2 3 4 5 6 7 8 9 |
// 通知客户端,token失效 callTokenLostToApp(){ let boswer = vm.config.getBrowser() if(boswer == 'isiOS'){ window.webkit.messageHandlers.tokenExpiredTransmit.postMessage(1); }else if(boswer == 'isAndroid'){ window.tokenExpiredTransmit.jsMethod(1) } }, |
实例2
1 2 3 4 5 6 7 8 9 |
// 关闭页面 closePageApp(cb){ let boswer = vm.config.getBrowser() // IOS 关闭页面 if(boswer == 'isiOS'){ // 这段代码是固定的,必须要放到js中 window.webkit.messageHandlers.closePage.postMessage(1); // 安卓关闭页面 }else if(boswer == 'isAndroid'){ window.closePage.jsMethod(1) } }, |
2.配合使用调用app原生的方法(h5页面需要回调和数据) // 从App获取UUID(手机唯一标识)
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 |
// 从App获取UUID(手机唯一标识) getSystemInfoFromApp(cb){ let boswer = vm.config.getBrowser() // IOS 获取UUID if(boswer == 'isiOS'){ // 这段代码是固定的,必须要放到js中 function setupWebViewJavascriptBridge(callback) { if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); } if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); } window.WVJBCallbacks = [callback]; var WVJBIframe = document.createElement('iframe'); WVJBIframe.style.display = 'none'; WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__'; document.documentElement.appendChild(WVJBIframe); setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0) } /*与OC交互的所有JS方法都要放在此处注册,才能调用通过JS调用OC或者让OC调用这里的JS*/ setupWebViewJavascriptBridge(function(bridge) { /*JS给ObjC提供公开的API,ObjC端通过注册,就可以在JS端调用此API时,得到回调。ObjC端可以在处理完成后,反馈给JS,这样写就是在载入页面完成时就先调用*/ bridge.callHandler('getSystemInfoFromApp', function(responseData) { if(cb && typeof cb == 'function'){ cb(responseData) }else{ return responseData } }) }) // 安卓获取UUID }else if(boswer == 'isAndroid'){ let systemInfo = window.AndroidWebView.getSystemInfoFromApp(); if(cb && typeof cb == 'function'){ cb(systemInfo) }else{ return systemInfo } } }, |
标红字段为调用的app端定义的方法名,需要app端定义方法配合 from:https://www.cnblogs.com/wendyAndJken/p/9318501.html
View Details今天升级Xcode 7.0 bata发现网络访问失败。 输出错误信息
1 |
The resource could not be loaded because the App Transport Security policy requires the use of a secure connection. |
Google后查证,iOS9引入了新特性App Transport Security (ATS)。详情:App Transport Security (ATS) 新特性要求App内访问的网络必须使用HTTPS协议。 但是现在公司的项目使用的是HTTP协议,使用私有加密方式保证数据安全。现在也不能马上改成HTTPS协议传输。 最终找到以下解决办法: 在Info.plist中添加NSAppTransportSecurity类型Dictionary。 在NSAppTransportSecurity下添加NSAllowsArbitraryLoads类型Boolean,值设为YES 看到很多同学修改后还是不能用添加一下截图: 在Filter中搜索Info.plist,选择Info.plist进行编辑 按照上面提到的方式添加信息,正确的修改会看到下图这个样子,注意类型NSAppTransportSecurity为Dictionary,NSAllowsArbitraryLoads为Boolean,复制粘贴的时候,不要多了空格,segment fault 页面上直接复制,经常会多一个出空格! 注意⚠️,单元测试下面也有一个Info.plist,修改那个文件是没有作用的! 补充说明 上面介绍的方法虽然解决了网络访问的问题,但是苹果提供的安全保障也被关闭了。 不过,按照国内的现状,关闭这个限制也许是更实际的做法。 至于原因就太多了,第三方SDK(几乎都是访问HTTP),合作伙伴接入(不能要求它们一定要支持HTTPS)。 如果你的App没有受到这些原因的限制,还是更建议你增加HTTPS支持,而不是关闭限制。 请大家根据项目的实际情况作调整。 出于安全考虑我们提倡使用HTTPS,退而求其次,优先考虑使用例外:将允许访问的域加入到配置列表中 @banxi1988 补充了配置的方法 对于实在不支持HTTPS的应该首先考虑添加例外 添加例外的方式也很简单: 左键Info.plist选择open with source code 然后添加类似如下的配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>qq.com</key> <dict> <key>NSIncludesSubdomains</key> <true/> </dict> <key>sina.com.cn</key> <dict> <key>NSIncludesSubdomains</key> <true/> </dict> </dict> </dict> |
根据自己需要的域名修改, NSIncludeSubdomains 顾名思义是包括子域的意思。 参考: App Transport Security support aka apps on iOS 9 don’t work #4560 711_networking_with_nsurlsession.pdf 总结: 苹果正在加大应用安全的管控,这个举措可以看出苹果对信息安全的重视,也暴露出大部分应用传输数据时都是未经过加密的,或使用私有方式加密,以至于苹果开始对开发者提出要求。 私有加密虽然一定程度上是安全的,但是终究不是一个长久之计。全世界这么多安全专家在维护HTTPS安全,早日使用HTTPS确保信息安全才是王道!也省去了私有加密协议的安全隐患! from:https://segmentfault.com/a/1190000002933776
View Details欢迎使用 React Native!这篇文档会帮助你搭建基本的 React Native 开发环境。如果你已经搭好了环境,那么可以尝试一下编写 Hello World。 Follow these instructions if you need to build native code in your project. For example, if you are integrating React Native into an existing application, or if you "ejected" from Create React Native App, you’ll need this section. 根据你所使用的操作系统、针对的目标平台不同,具体步骤有所不同。如果想同时开发 iOS 和 Android 也没问题,你只需要先选一个平台开始,另一个平台的环境搭建只是稍有不同。 如果阅读完本文档后还碰到很多环境搭建的问题,我们建议你还可以再看看由本站提供的环境搭建视频教程(macOS iOS、macOS Android、windows Android)、windows 环境搭建文字教程、以及常见问题。注意!视频教程或者其他网络上的博客和文章可能和本文档有所出入,请以最新版本的本文档所述为准! 开发平台: macOS 目标平台: iOS 安装依赖 必须安装的依赖有:Node、Watchman 和 React Native 命令行工具以及 Xcode。 虽然你可以使用任何编辑器来开发应用(编写 js 代码),但你仍然必须安装 Xcode 来获得编译 iOS 应用所需的工具和环境。 Node, Watchman 我们推荐使用Homebrew来安装 Node 和 Watchman。在命令行中执行下列命令安装:
1 2 |
brew install node brew install watchman |
如果你已经安装了 Node,请检查其版本是否在 v8.3 以上。安装完 Node 后建议设置 npm 镜像以加速后面的过程(或使用科学上网工具)。 […]
View Details由于谷歌商店国内访问不了,即使访问得了,国内许多安卓机也没有google play的框架,还是安装不了google商店的应用。想用安卓机开发啊,找度娘,终于在csdn的下载上,找到了个可用的~ Apk下载 csdn:http://download.csdn.net/download/yyh352091626/9176197
View Details1. DZNEmptyDataSet 这本应该是iOS中一个标准、内置的解决空table和collection view的方式。默认的如果你的table view是空的,屏幕就是空的。但这不是你能提供的最好的用户体验。 用了这个库,你只需要遵循一系列协议,iOS会优雅地接管你的collection view并且会正确、好看地显示给用户信息。很明显,每个iOS项目都应该采用。 这是完全可自定义的。 CocoaPods: pod ‘DZNEmptyDataSet’ GitHub 2. PDTSimpleCalendar 你的app是否需要一个简单、好看并且有效的日历组件呢? 现在你有了——PDTSimpleCalendar很有可能是最棒的iOS日历组件。有很多方式来自定义它,逻辑有效而且好看。 CocoaPods: pod 'PDTSimpleCalendar' GitHub 3. MagicalRecord 他们说,Core Data很简单。他们说,它很好很简单。哈哈,你是认真的吗,苹果?一顿陈词滥调的代码被添加到每个项目里,这真的不够优雅和简单。更不用说添加、移除和更新很多实体,保存上下文,为不同的环境创建不同的Core Data栈,等等等等。我当然很喜欢Core Data,但是苹果真的可以通过一个简单的好方法来简化它——MagicalRecord方法。 MagicalRecord的工作就像一个Core Data的包装,并且向开发者隐藏了所有无关的东西。如果你曾经用过活跃纪录模式(例如Ruby on Rails),那你已经掌握它了。如果你在app里用Core Data的话真的真心推荐这个库。 CocoaPods: pod 'MagicalRecord' GitHub 4. Chameleon 如果你读到了这一点,你是一个很好的程序员,而不是一个设计师。这就是为你准备的。 Chameleon是iOS的一个颜色框架。它用好看、摩登的扁平化颜色扩展了UIColor。它也给了我们能力来创建调色板,里面是我们自己定义的颜色。它可以做很多其他事,探索readme文件。如果你想要好看的应用程序,快把这个库加到你的项目里吧。 Chameleon基础扁平化颜色 CocoaPods: pod 'ChameleonFramework' GitHub 5. Alamofire Alamofire是一个用Swift写的优雅的网络库。你曾经用过AFNetworking吗?ALamofire是它的弟弟。年轻也更有才华,当然啦(AFNetworking是用Objective-C写的)。 需要做网络相关比如下载、上传、获取JSON等等?Alamofire是为你准备的。GitHub上8000人的选择不会错。 CocoaPods: pod 'MagicalRecord' GitHub 6. TextFieldEffects 你不觉得标准的UITextField有一点无聊吗?我也是——所以对TextFieldEffects说hello吧!我不会写太多,我只会展示你一些这个库可以做的例子: 是的,这些就是简单的易用的控制器。你甚至可以用storyboard里的IBDesignable! 不幸的是这个库不支持CocoaPods(如果你来自未来,而这在一些时间之前改变了的话,请在Twitter上让我知道),但它支持Carthage。你也可以简单的从GitHub下载项目,并且把它添加到你的workspace里。 Carthage: github "raulriera/TextFieldEffects" GitHub 7. GPUImage 你曾经创建过一个摄像机app吗?如果没有,看完这个库你就肯定会的。 GPUImage可能性 GPUImage提供我们一个GPU-accelerated摄像头效果(图像和视频都可以),熊熊燃烧般的速度。App Store里有几百个app使用这个库——其中就有我的一个: 我的一个app中用的GPUImage GitHub上8869个收藏并且还在持续增加。 CocoaPods: pod 'GPUImage' GitHub 8. iRate 在App Store获得更多评价最好的方式是什么?我没有明确的数据来回答这个问题,但如果要我来猜测的话,我会说只要简单的询问用户就可以了。也许这是一个老套的方式——大部分开发者现在创建自定义的app内置提醒——但如果你没有时间或者不想所有事都从头做起,用iRate比不用要好。并且这就是iRate——一个小库,你包含在你的项目里并且忘记询问用户去评价了——iRate会自动替你完成,在合适的时间里。 CocoaPods: pod 'iRate' GitHub 9. GameCenterManager 喜欢或讨厌一个人,在这种情况下管理Game Center非常简单,只需要一点我们最著名的反模式的帮助(你的游戏里只有Game Center,对吧?) 诚实地说,在iOS里香草管理Game Center并不是那么困难,但用这个库就是简单和快速。更好的是好的敌人。 […]
View Details在众多行业中,程序员属于高薪职业。无论是在国外还是国内,程序员的薪金水平普遍高于其他行业的工作岗位。 高薪的诱惑和充满挑战性的工作,令程序员一直成为备受欢迎的职业。在今年年初,Glassdoor发布的一份调查报告指出,在美国,程序员的就业情况仍然向好。据报告显示,在排名前25位的最能赚钱和需求量最高的工作岗位中,超过一半以上的岗位要求求职人员具备编程技术。因此,要想获得高薪不是一件容易的事情,你得有过硬的本领。 14种最具“吸金”能力的编程语言 据美国Rasmussen College(拉斯姆森学院)在2015年5月发表的一篇文章显示,在数以百计的编程语言中,以下14种编程语言最具“吸金”能力。 文章指出,这个结果是拉斯姆森学院收集了在2014年发布的1800万个招聘广告,以“平均年薪”和“招聘职位”两个指标为基础进行分析而得出来的。 (数据来源:Rasmussen College) 而在Indeed.com今年发布的调查数据则显示,根据编程工作的数量,排在前九位的编程语言如下: 图片来源:www.indeed.com 学习哪种编程语言可以赚到更多钱? 不同的编程语言适合不同的系统,不同的工程师也需要掌握不同的编程语言。 后台或服务器端的程序员通常都懂得Python, Ruby, PHP, Java或 .Net以及数据库的知识。前端或客户端的程序员掌握的编程语言主要是HTML, CSS和JavaScript,能力全面的程序员还具有设计能力。 移动应用的程序员懂得的语言是用于iOS 的Objective-C 或安卓系统的Java, 还有用于移动网站的HTML/CSS,他们当中有些人还懂得服务器的知识。3D或游戏开发者懂得 C/C , OpenGL和动画,同时具有艺术能力的程序员会更有优势。高效程序员懂得C/C 和Java,有的人还有数学和定量分析的能力。 如果你并不介意工程师的类型,Python, Objective-C, JavaScript, HTML和CSS这五种语言是值得学习的。因为每年它们都会出现在“最受欢迎的编程语言”名单中。此外,作为程序员,你还应该学习一些数据库,例如MySQL, MongoDB,而且要学习如何使用它来编程。 出处:网易科技 from:http://www.oschina.net/news/75295/these-programming-language-programmers-pay-the-highest
View DetailsReactNative是Facebook开源的一种实现移动跨平台开发的解决方案,目前在业界得到广泛应用,这里有非常详细的中文使用指南。本文主要分享RN源码中一些值得大家学习或者借鉴的代码或者编写技巧等,供大家学习参考。 整个RN库包含10多个工程,有兴趣的童鞋可以下载源码查看具体细节,在此不再展开。 宏定义巧用 整个ReactNative源码工程中用到了大量的宏定义,包括RCT_EXTERN、RCT_NOT_IMPLEMENTED、RCT_EXPORT_METHOD以及RCT_EXPORT_MODULE等申明宏或者功能宏。通过宏定义的方式,可以非常方便嵌入功能代码或者逻辑实现,重用代码的同时又保持了代码的整洁性。 比如,ProtocolKit工程中,作者通过宏定义@defs将Protocol接口巧妙的实现在.h文件中,代码简介明了,又不失功能完整性。当然,RN工程中,RCT_NOT_IMPLEMENTED宏也有相似作用,实际项目中各位也可以尝试通过宏定义实现一些常用功能模块。 关于iOS宏定义的文章有很多,在此推荐两篇非常不错的文章:RAC中必须要知道的宏、ios宏的使用和技巧。 环境变量 iOS开发中,各位对#ifdef DEBUG应该非常熟悉,通过判断该条件,可以区别当前运行环境是Debug环境还是Release环境。比如Release环境下通过重定义NSLog以屏蔽所有日志输出: ? 1 2 3 4 5 #ifdef DEBUG #define NSLog(…) NSLog(__VA_ARGS__) #else #define NSLog(…) {} #endif 进一步,是否可以考虑只在联机调试环境下输出日志?此时就涉及联机调试环境的判断,环境变量正好可以解决该问题: Xcode可以在不同环境下自定义环境变量Environment Variables,通过在运行环境Run中自定义变量CI_USE_PACKAGER,此时便可在项目代码中通过getenv()函数判断当前运行环境: ? 1 2 3 if (getenv("CI_USE_PACKAGER")) { // to do… } 被忽略的硬键盘 相较于软键盘文字符号的输入,对于APP来说,硬键盘的应用开发似乎很容易被忽视,毕竟,通常情况下,硬键盘输入只会出现在模拟器环境下。 iOS7以后,系统定义有硬键盘响应交互类UIKeyCommand,通过UIKeyCommand,APP能够监听硬键盘的特定输入响应,比如Command+D等,当然,前提是APP需要首先监听该输入命令。 UIKeyCommand的使用非常简单,当需要在特定场景触发某一事件,但又不想影响界面显示的时候,不妨试试UIKeyCommand,具体使用可以看看这篇文章。 _cmd iOS官方文档中,_cmd表示当前方法的selector,你可以通过下面代码打印输出当前函数名: ? 1 NSLog(@"Current method: %@", NSStringFromSelector(_cmd)); 当然,实际项目中,你也可以这样使用: ? 1 2 NSNumber *rootTag = objc_getAssociatedObject(self, _cmd) ?: @1; objc_setAssociatedObject(self, _cmd, @(rootTag.integerValue + 10), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 瞧,是不是有点意思! kCFNull 相对于nil NSNull而言,kCFNull笔者接触较少,kCFNull可以理解为NSNull单例对象: ? 1 2 id null1 = (id)kCFNull; id null2 = [NSNull null]; 打印地址: ? 1 2 null1=(NSNull *)0x10426eaf0 null2=(NSNull *)0x10426eaf0 从上面测试结果可以看出它们其实指向同一地址, 可以简单理解为 kCFNull === [NSNull null]。 文本阴影NSShadow APP开发中,程序猿可能经常需要在图片或视频上显示文字,由于背景颜色跟文字颜色相近,导致文字看不清,比如时下火热的直播弹幕显示,为了确保文字显示清晰,开发者一般会配上阴影或者文字描边。 给文本添加阴影描边,系统提供有NSShadow类,可以这样使用: ? 1 2 3 4 5 6 NSShadow *shadow = [NSShadow new]; shadow.shadowOffset = CGSizeZero; shadow.shadowBlurRadius = 5.0f; shadow.shadowColor = [UIColor colorWithWhite:0.0f alpha:0.3f]; NSAttributedString *attString = [[NSAttributedString alloc] initWithString:@"www.olinone.com" attributes:@{NSShadowAttributeName: shadow, NSForegroundColorAttributeName: [UIColor whiteColor]}]; lbl.attributedText = attString; 实际效果是这样的,shadowBlurRadius值越小,文本描边越清晰 主线程判断 判断当前执行线程是否为主线程的方法有很多,比如: ? 1 2 […]
View DetailsSwift3中文网消息,Facebook为iOS开发者推出了Swift开发者工具包(SDK),开发者可以通过Github链接下载https://github.com/facebook/facebook-sdk-swift。目前这一SDK基于Swift2,不过Facebook称他们将很快推出Swift3的版本。 据悉,这一开发者工具包包括登陆和分享功能,同时也包含带有分析功能的社交图谱API。 Facebook在官方博客中宣称:“我们相信将Facebook社交能力拓展于iOS生态系统,对于我们来说非常之重要。” 显然,Facebook并不是第一个投资于Swift的大公司,IBM在Swift发布的第一天起就发布了相关的企业级的工具,如Swift沙盒功能。Facebook也在类似的事情,这一SDK的发布将在消费级领域推广Swift的使用。 来源:Swift3中文网 from:http://www.oschina.net/news/75243/facebook-ios-swift
View Details由dkhamsing发起的Open-Source iOS Apps收集了各种开源的iOS App,并进行了详细的分类,比如游戏、社交、健康、键盘、定位、多媒体、新闻、办公、安全以及小工具类等。截至目前,项目已收集了502款开源iOS应用,收获了7967+个Star,并吸引了109位Contributor的参与。 在此摘取部分与开发者密切相关的应用与其GitHub地址。欲阅览全部应用,可直接点击链接查阅「Open-Source iOS Apps」的README。 Developer AppLove:https://github.com/snowpunch/AppLove AppSlate:https://github.com/Taehan-Kim/AppSlate Bequest:https://github.com/splinesoft/Bequest Blink:https://github.com/blinksh/blink Charter:https://github.com/matthewpalmer/Charter wat:https://github.com/pj4533/wat GitHub CodeHub:https://github.com/thedillonb/CodeHub GitBucket:https://github.com/leichunfeng/MVVMReactiveCocoa Github-Swift:https://github.com/acmacalister/Github-Swift Monkey:https://github.com/coderyi/Monkey MrCode:https://github.com/haolloyin/MrCode OctoPodium:https://github.com/nunogoncalves/iOS-OctoPodium SwiftHub:https://github.com/sahandnayebaziz/StateView-Samples-SwiftHub Ionic Minds Mobile App:https://github.com/Minds/mobile Vegan Lists UK:https://github.com/dsgriffin/vegan-lists-uk Parse 2CITY:https://github.com/2city/2CITY-iOS Anypic in Objective-C:https://github.com/ParsePlatform/Anypic Anypic in Swift:https://github.com/kwkhaw/SwiftAnyPic AnyWall:https://github.com/ParsePlatform/AnyWall how-much:https://github.com/dkhamsing/how-much iBeaconTasks:https://github.com/TomekB/iBeaconTasks React Native 2048(App by Facebook):https://github.com/facebook/react-native/tree/master/Examples/2048 allyoop:https://github.com/wwayne/react-native-nba-app Around Me:https://github.com/bgryszko/react-native-example Assemblies:https://github.com/buildreactnative/assemblies ReactiveCocoa BrewMobile:https://github.com/brewfactory/BrewMobile C-41:https://github.com/ashfurrow/C-41 GroceryList:https://github.com/jspahrsummers/GroceryList HausClock:https://github.com/nottombrown/HausClock RxSwift Count It:https://github.com/PiXeL16/CountItApp GitHub API Client:https://github.com/tailec/boilerplate Kiosk:https://github.com/artsy/eidolon 出处:CSDN from:http://www.oschina.net/news/75258/502-opensource-ios
View Details