Wednesday, March 16, 2022

SegmentFault 最新的文章

SegmentFault 最新的文章


由 Figma 封停大疆,看国产 IDE 如何应对与突围?

Posted: 15 Mar 2022 08:07 PM PDT

3 月 12 日,UI 设计协作工具软件 Figma 封停大疆,中国企业使用国际软件的不确定性加剧。UI 设计工具的禁用是否只是开端?目前被国际软件和开源工具垄断的 IDE(集成开发环境)是否将成为下一个封停对象?

试想,作为一名算法工程师,如果有一天醒来发现,工作所必需的 Jupyter、PyCharm、VS Code 等 IDE 均无法使用了,该何去何从?

本文将与大家共同探讨,国产 IDE 该如何应对潜在的停用风险。

技术有国界,国产 IDE 突围正当时

3 月 12 日,美国在线设计软件企业 Figma 封停大疆等公司的账号,为国产软件的突围和崛起再一次敲响了警钟。

在复杂的环境形式下,不仅是商业软件,开源软件也难以保持"开放的净土"。早在 2019 年,Github 就对部分地区的开发者进行了限制,这些地区的开发者不仅无法正常使用 Github,甚至连私有仓库里的代码都无法访问。

随着我国数字经济的发展和数智化转型的推进,利用 AI 技术进行数据分析和挖掘成为必然趋势,而适用于算法开发的 IDE 则是支撑这一转型趋势不可或缺的基础工具。

目前中国数据科学家和算法工程师使用的 IDE 主要为 Jupyter、PyCharm 和 VS Code 等,虽为开源软件,但并不等于自主可控。试想,作为一名算法工程师,如果有一天醒来发现,工作所必需的 Jupyter 和 PyCharm 等 IDE 均无法使用了,该何去何从?

在风云变幻的技术环境下,需未雨绸缪,积极寻求可控的替代解决方案。构建国产 IDE 产品能力,攻坚正当时。

为什么长期没有优质国产 IDE?

从 1970s 是世界上第一个软件集成开发环境 - Maestro I-推出至今,IDE 工具逐渐呈百花齐放状态,可优质国产 IDE 在市场上仍为空白。"为什么一直没有优质的国产 IDE?"是一个持续被提起、但从未被认真探讨过的问题。我们认为主要有三大原因,总结如下,与各位技术极客共同探讨。

1. 技术实现挑战堪比开发操作系统

IDE 虽为应用软件,但其开发难度并不亚于研发一个操作系统。IDE 的核心价值在于让开发人员快速着手为新应用编写代码,提升开发体验和效率。为实现这一价值,IDE 将各种功能组件集中于同一工作台中,包括代码编辑、编译重构、调试、版本管理等。这一"集成"特性也意味着,IDE 的开发难度极高,它并非一个单纯的软件,而是一个复杂的系统,不仅要面临编译器、调试器等复杂功能组件的开发挑战,还要应对集成整合的复杂性。集成开发环境并非仅仅是各功能组件的堆砌,还要考虑对其的组织与调度。

2. 用户体验要求高进一步提升 IDE 开发门槛

IDE 的使用者为开发工程师,其对产品的性能和体验要求极高,进一步增加了 IDE 的开发难度。

IDP 在产品开发中识别到,算法工程师等开发人员最看重的 IDE"体验性"功能主要包括:

  • 数据源的快速接入与便捷的数据探索
  • 代码自动化,包括自动缩进、换行等格式自动化,以及智能代码补全功能和自动代码生成
  • 随时查看函数、常量的定义
  • 源码级的调试

这些功能仅仅存在是不够的,其性能和体验达到让用户满意的程度,对于 IDE 的开发来说可谓是难上加难。

3. 中外环境差异导致国内对基础软件投入较弱

我国计算机和互联网行业起步相对较晚,国外企业已在基础软件领域取得了垄断性地位。在失去先发机遇和优势的情况下,国内企业在发展路径选择上,更多是基于国际基础软件系统主打面向消费者的应用。公开数据显示,国产基础软件在国内市场份额仅为 5%,且多借鉴开源软件,纯自研较少。

互联网行业发展的十几年来,"重硬轻软","重应用研发轻基础研发","赚快钱"等观念在国内市场长期存在。即使有政策鼓励,也鲜少有企业愿意对需长期耕耘、但可能无法获得收益的基础软件领域进行投入。

IDE 工具更是如此。IDE 的商业化长期面临双重夹击,一方面是免费的开源软件,一面是深耕 IDE 多年的 Jetbrains 等国际龙头厂商。开发周期长,投入高,商业化难度大,导致无论是国内资本还是人才,都极少流入 IDE 赛道。

但近几年,该情况已得到扭转,国产基础软件开始明显受到资本的追捧,IDE 等基础软件的发展土壤逐渐形成。

如何打造优质 IDE?

那么,在国产 IDE 发展的黄金时代,应该如何打造一款优质的 IDE 工具?基于 IDP 开发过程中的经验,我们认为打造优质 IDE 的关键成功因素主要有以下四点。

攻坚自研核心技术:技术是基础软件的核心护城河。IDP 坚持自研,包括 WebOS 级的界面、后端 Kernel 运行、任务调度和资源管理均为自主研发,为用户提供可靠、稳定、一体化的使用体验。

体验为王的极简设计:优质的体验是产品的核心。IDE 面对的用户是"严格挑剔"的工程师,在具有相对丰富的免费开源 IDE 选择的情况下,只有极致的产品品质和体验才能赢得用户的心智。IDP 坚持以工程师的文化进行产品开发,在产品设计中充分考虑数据科学家和算法工程师的使用习惯,坚持"简单、再简单"的原则,打造具有卓越品质、低使用门槛的易用 IDE。

产品快速、持续迭代更新:基础软件的开发应以长期而非昙花般爆款的心态耕耘产品,同时应快速迭代,以保证产品始终处于领先地位。TextMate、Sublime 等 IDE 日渐式微,版本更新周期久是主要原因。IDP 希望打造一款能够陪伴中国数据科学家和算法工程师共同成长的长青 IDE,我们将紧密追踪技术、市场和用户行为的变化,快速响应,不断优化,持续满足用户需求。

开源开放与生态共荣:开源对于产品的长期发展至关重要。IDP 后续将开源其 IDE 产品模块,通过社区积极聆听用户声音,加速产品的迭代与完善。同时,IDP 将以开放共荣的原则,与各插件、工具和云平台等合作,进一步便捷用户的使用。

国产基础软件迎来发展的黄金时代,希望可以有更多的企业、开发者加入这一浪潮,不仅是为形式上的国产替代,而是为中国的 IDE 等基础软件也能在世界竞争格局中占有重要的一席之地。

了解IDP:
https://baihai.co/

别再问WiFi密码了,HMS Core统一扫码服务让手机一键联网

Posted: 08 Mar 2022 06:09 PM PST

现代生活离不开网络,在餐厅、商场等公共场所,手机连接WiFi一直是高频使用场景。虽然公共场所的免费WiFi越来越多,但网络连接过程却很麻烦。有的需要打开网页注册或点击广告链接才能上网,还有的要求下载特定App才能连接。

那么有没有什么更方便的联网方式呢?"扫码联网"提出了解决方案,商家可以在店放置包含WiFi信息的二维码。用户打开手机相机扫码即可连接WiFi,还支持将二维码分享给身边好友,使入网更快、更直观,并且无需担心隐私泄露、被推送无用信息等问题。

效果展示

实现原理

通过HMS Core统一扫码服务的码生成和扫码能力,轻松实现扫码连WiFi这一场景。

开发实战

一、构建扫码功能

开发准备

1.1 配置华为Maven仓地址

在项目中"buildscript > repositories"中配置HMS Core SDK的Maven仓地址。在"allprojects > repositories"中配置HMS Core SDK的Maven仓地址。

buildscript {     repositories {         google()         jcenter()         // 配置HMS Core SDK的Maven仓地址。         maven {url 'https://developer.huawei.com/repo/'}     } }  allprojects {     repositories {         google()         jcenter()         // 配置HMS Core SDK的Maven仓地址。         maven {url 'https://developer.huawei.com/repo/'}     } } Gradle 7.0版本后,"allprojects > repositories"配置已迁移到项目级"settings.gradle"文件中。"settings.gradle"文件配置示例如下: dependencyResolutionManagement {     ...     repositories {         google()         jcenter()          maven {url 'https://developer.huawei.com/repo/'}     } }

1.2 添加编译依赖

位置应用build.gradle

dependencies{     //Scan SDK     implementation 'com.huawei.hms:scan:2.3.0.300' }

1.3 代码混淆

在应用级根目录下打开混淆配置文件"proguard-rules.pro",加入排除HMS Core SDK的混淆配置脚本。

-ignorewarnings -keepattributes *Annotation* -keepattributes Exceptions -keepattributes InnerClasses -keepattributes Signature -keepattributes SourceFile,LineNumberTable -keep class com.huawei.hianalytics.**{*;} -keep class com.huawei.updatesdk.**{*;} -keep class com.huawei.hms.**{*;}

1.4 Manifest.xml添加权限

<!--相机权限--> <uses-permission android:name="android.permission.CAMERA" /> <!--文件读取权限--> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

1.5 申请动态权限

ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, requestCode);

1.6 申请权限结果

@Override     public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {         super.onRequestPermissionsResult(requestCode, permissions, grantResults);                  if (permissions == null || grantResults == null) {             return;         }         // 申请权限成功或已有权限         if (requestCode == CAMERA_REQ_CODE) {             // Default View Mode方式扫码接口             // 参数说明:             // activity     请求扫码的activity              // requestCode     扫码请求的请求码,用于鉴定activity返回时是否从扫码界面返回。             // option         扫码格式选项,可以置为"null"             ScanUtil.startScan(this, REQUEST_CODE_SCAN_ONE, new HmsScanAnalyzerOptions.Creator().create());         }     }         

1.7 回调接口接收扫码结果,相机扫码和导入图片扫码均通过该接口返回。

@Override     protected void onActivityResult(int requestCode, int resultCode, Intent data) {         super.onActivityResult(requestCode, resultCode, data);          if (resultCode != RESULT_OK || data == null) {             return;         }          if (requestCode == REQUEST_CODE_SCAN_ONE) {             // 导入图片扫描返回结果             HmsScan hmsScan = data.getParcelableExtra(ScanUtil.RESULT);             if (hmsScan != null) {                 // 码值结果 rawResult自定义TextView                 rawResult.setText(hmsScan.getOriginalValue());             }         }      }

二、构建码生成功能

构建扫码功能同样需要配置Marven仓地址,添加编译依赖和配置混淆脚本,参考上方1.1,1.2和1.3

2.1 Manifest.xml添加权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

2.2 申请动态权限

ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},requestCode);

2.3 申请权限结果

@Override     public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {         if (permissions == null || grantResults == null) {             return;         }          if (grantResults[0] == PackageManager.PERMISSION_GRANTED && requestCode == GENERATE_CODE) {             Intent intent = new Intent(this, GenerateCodeActivity.class);             this.startActivity(intent);         }     }

2.4 生成二维码

public void generateCodeBtnClick(View v) {         try {               HmsBuildBitmapOption options = new HmsBuildBitmapOption.Creator()                     .setBitmapMargin(margin)                     .setBitmapColor(color)                     .setBitmapBackgroundColor(background)                     .create();             resultImage = ScanUtil.buildBitmap(content, type, width, height, options);             barcodeImage.setImageBitmap(resultImage);          } catch (WriterException e) {             Toast.makeText(this, "Parameter Error!", Toast.LENGTH_SHORT).show();         }      }

2.5 保存二维码

public void saveCodeBtnClick(View v) {         if (resultImage == null) {             Toast.makeText(GenerateCodeActivity.this, "Please generate barcode first!", Toast.LENGTH_LONG).show();             return;         }         try {             String fileName = System.currentTimeMillis() + ".jpg";             String storePath = Environment.getExternalStorageDirectory().getAbsolutePath();             File appDir = new File(storePath);             if (!appDir.exists()) {                 appDir.mkdir();             }             File file = new File(appDir, fileName);             FileOutputStream fileOutputStream = new FileOutputStream(file);             boolean isSuccess = resultImage.compress(Bitmap.CompressFormat.JPEG, 70, fileOutputStream);             fileOutputStream.flush();             fileOutputStream.close();             Uri uri = Uri.fromFile(file);             GenerateCodeActivity.this.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));             if (isSuccess) {                 Toast.makeText(GenerateCodeActivity.this, "Barcode has been saved locally", Toast.LENGTH_LONG).show();             } else {                 Toast.makeText(GenerateCodeActivity.this, "Barcode save failed", Toast.LENGTH_SHORT).show();             }         } catch (Exception e) {             Toast.makeText(GenerateCodeActivity.this, "Unkown Error", Toast.LENGTH_SHORT).show();         }     }
欲了解更多HMS Core统一扫码服务详情,请参阅:

https://developer.huawei.com/...

华为开发者联盟官网
获取开发指导文档
参与开发者讨论请到Reddit社区
下载demo和示例代码请到Github
解决集成问题请到Stack Overflow

No comments:

Post a Comment