首页 文章 精选 留言 我的

精选列表

搜索[native],共6255篇文章
优秀的个人博客,低调大师

React Native 源码笔记——你知道几条?

ReactNative是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以屏蔽所有日志输出: #ifdef DEBUG #define NSLog(...) NSLog(__VA_ARGS__) #else #define NSLog(...) {} #endif 进一步,是否可以考虑只在联机调试环境下输出日志?此时就涉及联机调试环境的判断,环境变量正好可以解决该问题: Xcode可以在不同环境下自定义环境变量Environment Variables,通过在运行环境Run中自定义变量CI_USE_PACKAGER,此时便可在项目代码中通过getenv()函数判断当前运行环境: if (getenv("CI_USE_PACKAGER")) { // to do... } 被忽略的硬键盘 相较于软键盘文字符号的输入,对于APP来说,硬键盘的应用开发似乎很容易被忽视,毕竟,通常情况下,硬键盘输入只会出现在模拟器环境下。 iOS7以后,系统定义有硬键盘响应交互类UIKeyCommand,通过UIKeyCommand,APP能够监听硬键盘的特定输入响应,比如Command+D等,当然,前提是APP需要首先监听该输入命令。 UIKeyCommand的使用非常简单,当需要在特定场景触发某一事件,但又不想影响界面显示的时候,不妨试试UIKeyCommand,具体使用可以看看这篇文章。 _cmd iOS官方文档中,_cmd表示当前方法的selector,你可以通过下面代码打印输出当前函数名: NSLog(@"Current method: %@", NSStringFromSelector(_cmd)); 当然,实际项目中,你也可以这样使用: NSNumber *rootTag = objc_getAssociatedObject(self, _cmd) ?: @1; objc_setAssociatedObject(self, _cmd, @(rootTag.integerValue + 10), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 瞧,是不是有点意思! kCFNull 相对于nil NSNull而言,kCFNull笔者接触较少,kCFNull可以理解为NSNull单例对象: id null1 = (id)kCFNull; id null2 = [NSNull null]; 打印地址: null1=(NSNull *)0x10426eaf0 null2=(NSNull *)0x10426eaf0 从上面测试结果可以看出它们其实指向同一地址, 可以简单理解为 kCFNull === [NSNull null]。 文本阴影NSShadow APP开发中,程序猿可能经常需要在图片或视频上显示文字,由于背景颜色跟文字颜色相近,导致文字看不清,比如时下火热的直播弹幕显示,为了确保文字显示清晰,开发者一般会配上阴影或者文字描边。 给文本添加阴影描边,系统提供有NSShadow类,可以这样使用: 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值越小,文本描边越清晰 主线程判断 判断当前执行线程是否为主线程的方法有很多,比如: [NSThread isMainThread] pthread_main_np 在RN中,它是这样的: BOOL RCTIsMainQueue() { static void *mainQueueKey = &mainQueueKey; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ dispatch_queue_set_specific(dispatch_get_main_queue(), mainQueueKey, mainQueueKey, NULL); }); return dispatch_get_specific(mainQueueKey) == mainQueueKey; } 当然,由于无法查看NSThread内部实现机制,暂时无法了解孰优孰劣,不过,[NSThread isMainThread]貌似足矣! volatile不简单 在百科中,是这样描述它的:就像大家更熟悉的const一样,volatile是一个类型修饰符,它是被设计用来修饰被不同线程访问和修改的变量。作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。 简单说,被volatile修饰的变量是多线程安全的,其次,不会因为编译器优化导致读值出错。关于编译器编译优化可以看看这篇文章。 iOS开发中确保多线程安全的方法有很多,原子操作、线程锁、单线程执行等等,本人也写过相关文章iOS开发多线程同步。 在RN中,通过volatile修饰符,巧妙实现了多线程取消操作: __block volatile uint32_t cancelled = 0; if (!cancelled) { // to do... } OSAtomicOr32Barrier(1, &cancelled); 通过原子性操作访问被volatile修饰的cancelled对象即可保障函数只执行一次。想想大家熟悉的单例dispatch_once_t,现在让你设计单例对象,你又会如何设计了? + (instancetype)sharedInstance { static RCTWebSocketManager *sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [self new]; }); return sharedInstance; } 结构体Struct 说起Struct,不知各位对它印象如何?大学C课本中学过?NSObject类class原型貌似有讲? struct iOSDev { NSString *nickName; }; OC中一个简单的结构体,在Swift中,Struct也可以这样写: struct iOSDev { var nickName : String func getBusinessCard() -> String { return "\(nickName),幽默的iOS开发者!" } }; let iOSOlinone = iOSDev(nickName: "olinone") print(iOSOlinone.getBusinessCard()) getBusinessCard为结构体函数,是不是感觉很方便!其实OC中也可以这样写: struct iOSDev { NSString *nickName; NSString *getBusinessCard() { return [NSString stringWithFormat:@"%@,幽默的iOS开发者!", nickName]; } }; iOSDev iosDev = iOSDev{@"olinone"}; NSLog(@"%@", iosDev.getBusinessCard()); 当然,为Struct添加函数并不是C语言特性,而是C++特性,因此,为了编译通过,你需要将.m文件修改成.mm文件 Struct有其使用的特殊场景,相较于Class,合理的使用Struct可以使代码更加整洁。同时,为了适应Swift中Struct强大特性,可以试着在OC项目中尝试Struct 最后,给大家来个段子吧: 话说一美女要在两个男人之间做选择,一个年纪大,长的丑,是个千万富翁,另一个年轻,帅气,iOS开发程序猿。 她对他们说,我会给你们一人一张纸条,写着我愿意的那张就是我的选择。 富翁打开纸条,看见上面写着我愿意,于是搂着她,坐上豪车高兴的走了。 年轻的小伙很伤心,打开纸条看见上面写着:“等我一个月~” 文章转载自 开源中国社区[http://www.oschina.net]

优秀的个人博客,低调大师

AI改变世界,美团改变AI Native

# **刚发布没两天。** 美团的AI浏览器就翻车了。 3月2日,美团光年之外团队高调宣布Tabbit AI浏览器公测。号称打磨半年,免费使用,聚合DeepSeek、Kimi、通义千问等顶尖大模型。 发布会的文案写得很漂亮,工作交给Tabbit,时间留给自己。 结果3月3日,一个独立开发者发了条帖子,直接把事情搞大了。 ![image](https://developer.qcloudimg.com/http-save/yehe-5421023/455dba9578f99be8246263c0fc54f54b.png) image ## **一张对比图,炸出来的真相** 网友梦溪睡了吗在社交平台上发帖,称美团的AI浏览器Tabbit抄袭其个人产品陪读蛙的代码,并放出了两款产品界面的对比图。 帖子里写得很直白。 几千亿市值的公司,白嫖嫖到我头上了,shame on you。 左边是美团AI浏览器,右边是他的产品。 界面几乎一模一样。 这还不是最要命的。 有技术爱好者去扒了Tabbit的源代码和资源文件。结果发现了什么? 开发者甚至在源代码和资源中发现Read Frog相关的字符串名称,这可以坐实Tabbit确实使用陪读蛙项目来构建翻译之类的功能。 Read Frog,就是陪读蛙的英文名。 代码里居然还留着原项目的名字。 这波操作,属实有点离谱。 ![image](https://developer.qcloudimg.com/http-save/yehe-5421023/344544912c839250b424b5c24912850b.png) image ## **GPL协议,你美团法务不知道吗** 问题的核心在于,陪读蛙是一款开源AI浏览器扩展工具,定位为沉浸式语言学习助手。 开源意味着代码公开,任何人都可以看,可以用。 但开源有协议啊。 网友表示,根据GPL协议,使用他的代码的产品都需要开源,而美团并未开源Tabbit。 GPL-3.0协议,在开源界号称最具传染性的协议。 什么叫传染性? 对于在逻辑上与开源代码有关联性且整体发布的衍生作品,只要其中有一部分适用了GPL V3协议发布,那么整个衍生作品都必须适用GPL V3协议而公开。 翻译成人话就是,你用了我的GPL代码,你整个产品都要开源。 不开源?那就是侵权。 Tabbit浏览器按照开源许可证协议也必须整体开源,光年之外没有将Tabbit整体开源就属于违反许可证的做法。 问题来了。 Tabbit开源了吗? 没有。 ![image](https://developer.qcloudimg.com/http-save/yehe-5421023/b879819fd4db4dc98c1547b5bfec4784.png) image ![image](https://developer.qcloudimg.com/http-save/yehe-5421023/e6eb53d2a852b098925e7e9a91c1e541.png) image ## **这事儿在法律上能赢吗** 很多人可能会问,GPL协议在国内有用吗?大公司随便白嫖,你能拿他怎么样? 还真能。 近日,一起关于GPL版权纠纷案裁判文书公示。一审判决书显示,GPL3.0协议是一种民事法律行为,具有合同性质,可认定为授权人与用户间订立的著作权协议,属于我国合同法调整的范围。 国内法院认的。 而且不只是认,还判过赔钱的案子。 根据开源软件的特性,GPL3.0协议规定的使用条件系授权人许可用户自由使用的前提条件,亦即协议所附的解除条件。一旦用户违反了使用的前提条件,将导致GPL3.0协议在授权人与用户之间自动解除,用户基于协议获得的许可即时终止。用户实施的复制、修改、发布等行为,因失去权利来源而构成侵权。 什么意思? 你违反GPL协议,你的授权自动终止。继续用,就是侵权。 法院据此判决玩友公司停止提供含有侵权沙盒分身功能源代码的四款软件的下载、安装和运营服务并赔偿罗盒公司经济损失及维权合理开支共计50万元。 这是国内首例GPL侵权判赔案。50万。 美团如果真的用了陪读蛙的代码,且没有按照GPL协议开源,法律风险是实实在在的。 ## **更骚的操作来了** 事情还没完。 有网友在扒Tabbit的时候,居然扒出了美团使用的API地址和对应的密钥。 然后呢? 然后大量网友把这些接口接入到自己的项目里,免费白嫖美团的额度。 你白嫖开源社区,我白嫖你的API。 这波属于因果循环,报应不爽。 虽然这个操作也不太合适,但说实话,围观群众的心情可以理解。 ![image](https://developer.qcloudimg.com/http-save/yehe-5421023/f3237c7ed3448db900764307ad144506.png) image ![image](https://developer.qcloudimg.com/http-save/yehe-5421023/5d09ace1d32627556e23b8d2380cc91f.png) image --- ## **个人开发者的困境** 这件事最让人唏嘘的,其实是独立开发者的处境。 作为Read Frog开发者,其实平时工作日有正式工作。 他是一边上班一边维护这个项目的。 陪读蛙可无缝接入多家大模型服务,你可以根据场景选择更合适的提供商。同时允许自定义Api Key,完全在本地运行,不依托于远程服务。 功能做得不错,用户评价也好,还是开源免费为爱发电的。 结果呢? 几千亿市值的大公司,直接拿去用了。界面抄了,代码用了,连字符串名字都没改。 然后该大公司高调开发布会,说我们打磨了半年。 打磨了半年,打磨了谁的代码? 个人或者小团队的开源作品的话,就算被不遵守许可证的盗版了也没什么办法。 这话说得扎心,但也是现实。 个人没钱没势,公司有资源敢赌。维权成本高得吓人,很多独立开发者只能选择放弃。 ![image](https://developer.qcloudimg.com/http-save/yehe-5421023/a86f6526fae49dbd269e383d939323c9.png) image ## **美团到底在想什么** 说实话,这件事发生在美团身上,我是有点意外的。 美团旗下光年之外团队宣布,其全新产品Tabbit AI浏览器进入公测。作为服务于上班族、在校学生及内容创作者等人群的AI原生浏览器,Tabbit将网页浏览、全网搜索、AI对话与复杂任务执行融为一体。 定位挺高端的。 ![image](https://developer.qcloudimg.com/http-save/yehe-5421023/8fdefe8bc83ab947272065576b9eba09.png) image Tabbit是美团光年之外团队推出的AI原生浏览器,从底层重构浏览体验,定位为智能工作伙伴。 从底层重构。 底层用的是独立开发者的开源代码,然后你告诉我从底层重构? 这就很尴尬了。 谁掌握了浏览器,谁就掌握了用户真实网络行为的训练数据,谁就有可能训练出最懂用户的个人AI代理。 浏览器是个好赛道,美团想下场可以理解。 但你堂堂几千亿市值的公司,连开源协议都不尊重,这合适吗? 光年之外当年可是王慧文豪言要打造中国OpenAI的团队。 打造中国OpenAI,从抄袭个人开发者开始? ## **这事儿后续会怎么样,美团道歉了** 就在大家以为这事要闹上法庭的时候,剧情突然反转。 3月3日,陪读蛙作者发布了最新声明。 在问题被指出后,Tabbit团队第一时间与作者取得联系,并对项目使用情况进行了说明与内部自查。从沟通过程来看,对方态度积极、处理及时。 美团主动联系了。 而且动作很快。 作者也确认,本次问题并非出于主观恶意,而是对开源协议理解和合规流程不够严谨所致。 说白了,不是故意的,是不懂规矩。 最关键的来了。 目前相关代码已完成开源处理,双方也在进一步沟通后续事宜。 开源了。 按照GPL协议的要求,开源了。 这波处理,说实话,比我预想的要好。 ![image](https://developer.qcloudimg.com/http-save/yehe-5421023/dd90b29bc306a70fe2bd0abf76b52289.png) image ## **最后说两句** 这件事能这样收场,其实是最好的结果。 开源社区的健康发展,离不开规则意识与相互尊重。 作者在声明里写了一段话,我觉得说得挺好的。 作为一名开发者,也作为中国人,他乐于看到国内AI浏览器与技术产品不断进步、走得更远。在尊重开源规则与作者权益的前提下,技术合作与良性发展才是更值得期待的方向。 格局打开了。 没有揪着不放,没有狮子大开口,而是选择了和解与共建。 美团这边也算是知错就改。被指出问题后没有装死,没有冷处理,第一时间沟通,第一时间整改,第一时间开源。 这才是大公司该有的态度。 当然,这件事也给所有企业提了个醒。 用开源代码之前,先看清楚协议。GPL、MIT、Apache,每个协议的要求都不一样。别等到出了事再补救,那时候口碑已经受损了。 合规这件事,不是成本,是底线。 希望这次的事情能成为一个正面案例。 企业尊重开源协议,开发者愿意沟通合作,社区理性讨论而非一味谩骂。 这样的生态,才能让更多人愿意参与开源,才能让技术真正向前走。 Tabbit浏览器本身的产品理念其实挺好的,工作交给AI,时间留给自己。 希望它能在合规的基础上越做越好。 也希望陪读蛙能获得更多关注和支持。 毕竟,独立开发者为爱发电,值得被看见。 *开源精神的核心是共享与尊重,你怎么看这次的和解?欢迎评论区聊聊。*

优秀的个人博客,低调大师

云原生(cloud native)是什么,怎么理解

很多人都会问“到底什么是云原生”,对此,CNCF 官方大使、阿里云容器平台高级技术专家张磊曾经做过精彩的解释。 实际上,云原生是一条最佳路径或者最佳实践。更详细的说,云原生为用户指定了一条低心智负担的、敏捷的、能够以可扩展、可复制的方式最大化地利用云的能力、发挥云的价值的最佳路径。 因此,云原生其实是一套指导进行软件架构设计的思想。按照这样的思想而设计出来的软件:首先,天然就“生在云上,长在云上”;其次,能够最大化地发挥云的能力,使得我们开发的软件和“云”能够天然地集成在一起,发挥出“云”的最大价值。 所以,云原生最大的价值和愿景,就是认为未来的软件,会从诞生起就生长在云上,并且遵循一种新的软件开发、发布和运维模式,从而使得软件能够最大化地发挥云的能力。说到了这里,你也可以思考一下为什么容器技术具有革命性? 其实,容器技术和集装箱技术的革命性非常类似,即:容器技术使得应用具有了一种“自包含”的定义方式。所以,这样的应用才能以敏捷的、以可扩展可复制的方式发布在云上,发挥出云的能力。这也就是容器技术对云发挥出的革命性影响所在,所以说,容器技术正是云原生技术的核心底盘。 云原生的技术范畴 云原生的技术范畴包括了以下几个方面: 第一部分是云应用定义与开发流程。这包括应用定义与镜像制作、配置 CI/CD、消息和 Streaming 以及数据库等。 第二部分是云应用的编排与管理流程。这也是 Kubernetes 比较关注的一部分,包括了应用编排与调度、服务发现治理、远程调用、API 网关以及 Service Mesh。 第三部分是监控与可观测性。这部分所强调的是云上应用如何进行监控、日志收集、Tracing 以及在云上如何实现破坏性测试,也就是混沌工程的概念。 第四部分就是云原生的底层技术,比如容器运行时、云原生存储技术、云原生网络技术等。 第五部分是云原生工具集,在前面的这些核心技术点之上,还有很多配套的生态或者周边的工具需要使用,比如流程自动化与配置管理、容器镜像仓库、云原生安全技术以及云端密码管理等。 最后则是 Serverless。Serverless 是一种 PaaS 的特殊形态,它定义了一种更为“极端抽象”的应用编写方式,包含了 FaaS 和 BaaS 这样的概念。而无论是 FaaS 还是 BaaS,其最为典型的特点就是按实际使用计费(Pay as you go),因此 Serverless 计费也是重要的知识和概念。 MBaaS(Mobile Backend as a Service),简称 BaaS FaaS(Function as a Service) 总的来说,云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。除了容器、Kubernetes、Service Mesh等当前比较有代表性的技术,很多企业也在边缘计算方面开展了很多工作 基础设施向云演进的意义 其实,传统的应用所依赖的基础设施正在经历一个向云演进的过程,在此过程中,为我们提供了两个非常重要的优点。 第一个优点是基础设施的一致性和可靠性。同样一个镜像,无论是在美国打开,在中国打开,还是在印度打开都是一样的。并且其中的 OS 环境对于应用而言都是一致的。而对于应用而言,它就不需要关心容器跑在哪里,这就是基础设施一致性非常重要的一个特征。 第二个优点即这样的镜像本身就是自包含的,其包含了应用运行所需要的所有依赖,因此也可以漂移到云上的任何一个位置。 此外,云原生的基础设施还提供了简单、可预测的部署和运维能力。由于现在有了镜像,应用还是自描述的,通过镜像运行起来的整个容器其实可以像 Kubernetes 的 Operator 技术一样将其做成自运维的,所以整个应用本身都是自包含的行为,使得其能够迁移到云上任何一个位置。这也使得整个流程的自动化变得非常容易。 应用本身也可以更好地扩容,从 1 个实例变成 100 个实例,进而变成 1 万个实例。最后,我们可以通过不可变的基础设施来快速部署周围的管控系统和支撑组件。因为,这些组件本身也是容器化的,是符合不可变基础设施理论的组件。这些就是不可变基础设施为用户带来的最大优点。 本文转载自https://mp.weixin.qq.com/s/lbXH0Zk89A9Sf-yy8oveDA

优秀的个人博客,低调大师

Android Native禁止使用系统私有库详解

系统私有库指的是,存放在android系统/system/lib/和/vendor/lib下面,但是Android NDK中没有公开API的lib库。 从Android N开始(SDK >= 24),通过dlopen打开系统私有库,或者lib库中依赖系统私有库,都会产生异常,甚至可能导致app崩溃。具体可以阅读官方文档说明。 这个变更会有怎样的影响呢? 曾经的美好 在以前,在ndk层面,我们是可以使用一些hack的手段得到系统的私有api的。 比如,你想使用虚拟机中的一些内部符号,在N以下版本,你可以这么搞 void *handle = dlopen("libart.so", RTLD_NOW); void *originFunc = dlsym(handle, "_ZNK3art6Thread13DumpJavaStackERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEE"); 这样你就能得到art::Thread::DumpJavaStack的函数指针,然后愉快地调用它了。 晴天霹雳 但是到了N以后, void *handle = dlopen("libart.so", RTLD_NOW); // 没问题,返回了handle指针。 void *originFunc = dlsym(handle, "_ZNK3art6Thread13DumpJavaStackERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEE"); // 失败!得到的originFunc为空! 这就很奇怪了,我们能够得到handle指针,就说明libart.so是找到了。但是为什么libart.so中却没有找到art::Thread::DumpJavaStack的符号呢? 看一下内存映射表,我们发现了一个有趣的东西 7de5d4d000-7de5d4e000 r-xp 00000000 fe:00 774 /system/fake-libs64/libart.so 7de5d4e000-7de5d4f000 r--p 00000000 fe:00 774 /system/fake-libs64/libart.so 7de5d4f000-7de5d50000 rw-p 00001000 fe:00 774 /system/fake-libs64/libart.so ... ... 7de6a04000-7de6feb000 r-xp 00000000 fe:00 1414 /system/lib64/libart.so 7de6feb000-7de6ffa000 r--p 005e6000 fe:00 1414 /system/lib64/libart.so 7de6ffa000-7de6ffd000 rw-p 005f5000 fe:00 1414 /system/lib64/libart.so 难怪,我们知道dlopen参数为libart.so的话,系统会先找到/system/fake-libs64/libart.so,而不是/system/lib64/libart.so。 而/system/fake-libs64/libart.so又是什么鬼?从名字上看,就知道他是个假的libart。在系统源码文件art/libart_fake/README.md中,我们找到了对他的解释, A fake libart made to satisfy some misbehaving apps that will attempt to link against libart.so. 这就是为了以防你们这些图谋不轨(misbehaving)的APP们做一些奇怪的事而专门设的套啊! 只要你自己的lib库依赖了libart.so或者试图打开libart.so,在linker查找libart.so时,因为fake-libs路径被设置在了查找路径表的靠前处,就会先找到/system/fake-libs64/libart.so,而不是真正的/system/lib64/libart.so。 设置fake-libs代码: @ frameworks/base/core/java/android/app/LoadedApk.java public static void makePaths(...) { ... // Add fake libs into the library search path if we target prior to N. if (aInfo.targetSdkVersion <= 23) { outLibPaths.add("/system/fake-libs" + (VMRuntime.is64BitAbi(aInfo.primaryCpuAbi) ? "64" : "")); } ... } 而这个/system/fake-libs64/libart.so的内容基本上的空的(art/libart_fake/fake.cc),所以在它里面当然什么符号都找不到啦~ 霸王硬上弓 既然如此,那我们在dlopen中直接指定lib的绝对路径总行了吧?像这样: void *handle = dlopen("/system/lib64/libart.so", RTLD_NOW); 可是很遗憾,它报了一个错: 01-11 13:16:10.413 19869-19869/com.patch.demo E/linker: library "/system/lib64/libart.so" ("/system/lib64/libart.so") needed or dlopened by "/data/app/com.patch.demo-1/lib/arm64/libbcpatch.so" is not accessible for the namespace: [name="classloader-namespace", ld_library_paths="", default_library_paths="/data/app/com.patch.demo-1/lib/arm64:/system/fake-libs64:/data/app/com.patch.demo-1/base.apk!/lib/arm64-v8a", permitted_paths="/data:/mnt/expand:/data/data/com.patch.demo"] 也就是说,你被允许访问的路径(包含ld_library_paths、default_library_paths、permitted_paths)只有 /data/app/com.patch.demo-1/lib/arm64 /system/fake-libs64 /data/app/com.patch.demo-1/base.apk!/lib/arm64-v8a /data /mnt/expand /data/data/com.patch.demo 所以,试图访问/system/lib64/下的libart.so当然是不行的啦。 真是魔高一尺道高一丈啊。 至此,我们算是知道了Google封杀在ndk中访问系统私有库的方法。本质是在linker中加入一系列校验机制来做限制。linker作为最基础的lib库链接器,所有链接行为都会被限制住。 缓兵之计 不过,在Android N,你可以指定APP的sdk为API级别23或更低。那么,对于以下灰名单中的lib,仍然可以正常使用: // TODO(dimitry): The grey-list is a workaround for http://b/26394120 --- // gradually remove libraries from this list until it is gone. static bool is_greylisted(const char* name, const soinfo* needed_by) { static const char* const kLibraryGreyList[] = { "libandroid_runtime.so", "libbinder.so", "libcrypto.so", "libcutils.so", "libexpat.so", "libgui.so", "libmedia.so", "libnativehelper.so", "libskia.so", "libssl.so", "libstagefright.so", "libsqlite.so", "libui.so", "libutils.so", "libvorbisidec.so", nullptr }; 这样的话,每次使用dlopen或者链接以上lib都会打印出一个警告,然后仍然正常执行原有功能。 同时Google也声明了,在将来的版本会将这些lib的支持也一并移除。因此,这只是提供了一个让你尽快在代码中去除相关依赖的过渡期。 可见,不久的将来就无法愉快地使用系统的非公开符号了。 突出重围 那我们真的就没办法了吗? 也不是绝对的,Android限制的只是dlopen这个途径,而我们访问内存是随心所欲的:) 方法就是,通过内存映射表找到libart.so的真实起始位置: 7de6a04000-7de6feb000 r-xp 00000000 fe:00 1414 /system/lib64/libart.so 7de6feb000-7de6ffa000 r--p 005e6000 fe:00 1414 /system/lib64/libart.so 7de6ffa000-7de6ffd000 rw-p 005f5000 fe:00 1414 /system/lib64/libart.so 然后在加载地址起始位置手动解析libart.so的elf格式,提取出所需符号的位置信息。相当于你自己实现linker原本的查找逻辑。 当然,这种遍历内存解析elf的实现是比较复杂的。因此,这一次Google算是封死了一大波底层hack的手段。 不过,网上仍然有很多绕过这个限制的方式,大家有兴趣的可以自己发掘一下。 也可以来这里与我们共同讨论技术

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册