{"id":22509517,"url":"https://github.com/gfaraday/cli","last_synced_at":"2026-02-08T13:36:08.953Z","repository":{"id":56828682,"uuid":"299575236","full_name":"gfaraday/cli","owner":"gfaraday","description":"faraday cli tool","archived":false,"fork":false,"pushed_at":"2024-04-12T03:38:24.000Z","size":182,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":6,"default_branch":"develop","last_synced_at":"2025-08-06T10:35:05.077Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gfaraday.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-09-29T09:57:34.000Z","updated_at":"2025-02-28T02:22:10.000Z","dependencies_parsed_at":"2024-04-12T04:44:37.339Z","dependency_job_id":null,"html_url":"https://github.com/gfaraday/cli","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/gfaraday/cli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gfaraday%2Fcli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gfaraday%2Fcli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gfaraday%2Fcli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gfaraday%2Fcli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gfaraday","download_url":"https://codeload.github.com/gfaraday/cli/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gfaraday%2Fcli/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29231509,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-08T13:10:22.947Z","status":"ssl_error","status_checked_at":"2026-02-08T13:08:18.779Z","response_time":57,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-07T01:29:23.265Z","updated_at":"2026-02-08T13:36:08.925Z","avatar_url":"https://github.com/gfaraday.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Faraday_CLI\n\n![Publisher](https://github.com/gfaraday/cli/workflows/Publisher/badge.svg?branch=master)\n![version](https://img.shields.io/pub/v/faraday?include_prereleases)\n\n`faraday_cli`(以下简称`cli`)是配合[g_faraday](https://github.com/gfaraday/g_faraday)进行模块化混合应用开发的命令行程序,帮助我们减少部分重复性工作让开发更高效\n\n## Features\n\n- [x] Generate Common\u0026Entry interface\n- [x] Package iOS\u0026Android framework/aar\n\n## Why\n\n### 桥接方法\n\n进行混合应用开发通常会有以下需求。有一个功能在ios/android两端已经实现，在flutter层需要调用，这时候就需要在flutter层来定义接口，然后在两端分别实现。下面我们来看一段代码示例\n\n``` dart\n\nclass EncryptUtils {\n\n    // 加密\n    static Future\u003cString\u003e encrypt(String content, Map\u003cString, dynamic\u003e options) {\n        return FaradayCommon.invokeMethod('SomeFeature#encrypt', {'content': content, 'options': options});\n    }\n\n    // 解密\n    static Future\u003cString\u003e decrypt(String encryptedContent, Map\u003cString, dynamic\u003e options) {\n        return FaradayCommon.invokeMethod('SomeFeature#decrypt', {'encryptedContent': encryptedContent, 'options': options});\n    }\n}\n\n```\n\n以上，我们在flutter中定义了加密和解密2个方法，接下来我们需要分别在ios/android的`FaradayCommon`中来实现代码如下(仅swift，kotlin类似)\n\n``` swift\n\nfunc handle(_ name: String, _ arguments: Any?, _ completion: @escaping (_ result: Any?) -\u003e Void) -\u003e Void {\n    if (name == \"SomeFeature#encrypt\") {\n        guard let content = args?[\"content\"] as? String else {\n                fatalError(\"Invalid argument: content\")\n        }\n        let options = args?[\"options\"] as? [String, Any]\n\n        // 使用以上参数来调用原生加密方法\n    } else if (name = \"SomeFeature#decrypt\") {\n        guard let encryptedContent = args?[\"encryptedContent\"] as? String else {\n                fatalError(\"Invalid argument: encryptedContent\")\n        }\n        let options = args?[\"options\"] as? [String, Any]\n\n        // 使用以上参数来调用原生解密方法\n    }\n    ...\n}\n\n```\n\n仔细看上述代码实现就会发现有很多重复代码片段，因此`cli`提供了对应的生成工具来实现代码生。(具体命令请见下述示例)\n\n### 路由注册\n\nflutter中一个典型的路由注册如下\n\n```dart\n// flutter\nMap\u003cString, RouteFactory\u003e routes = {\n    'first_page': (RouteSettings settings) =\u003e CupertinoPageRoute(\n        builder: (context) =\u003e FirstPage(0), settings: settings),\n    'home': (RouteSettings settings) =\u003e CupertinoPageRoute(\n        builder: (context) =\u003e HomePage(settings.arguments), settings: settings),\n    'flutter_tab_2': (RouteSettings settings) =\u003e CupertinoPageRoute(\n        builder: (context) =\u003e HomePage(settings.arguments), settings: settings),\n    'flutter_tab_1': (RouteSettings settings) =\u003e CupertinoPageRoute(\n        builder: (context) =\u003e EmbeddingPage(0), settings: settings),\n  };\n```\n\n``` swift\n\n// swift\n\nenum FaradayRoute {\n    // ---\u003e enum\n    // ---\u003e enum MainTabPage\n    case first_page\n    case home(Int id)\n    case flutter_tab_2(String name)\n    case flutter_tab_1\n}\n```\n\n上面的例子可以看出我们在3端需要定义很多`常量字符串`,如果任由开发者手动输入，ide没有任何提醒，那会非常容易出错。(具体命令下述会有相关示例)\n\n### 打包集成\n\n#### ios\n\n[官方集成方案](https://flutter.dev/docs/development/add-to-app/ios/project-setup)一共有3种，其中2中需要ios开发者本地由flutter开发环境，还有一种需要获取被人打包好的framework。这种开发体验对一个稍具规模的ios开发团队来说并不是特别友好。我们将采用 `pod 私有库`的方式在团队成员之间共享打包产物。同时对CI/CD流程提供支持\n\n#### android\n\n[android 官方方案](https://flutter.dev/docs/development/add-to-app/android/project-setup)对比ios来说，使用aar方式集成非常友好，只需要将编译产物放到大家都可以访问到的地址即可\n\n## How\n\n### 前置准备条件\n\n- 安装`faraday cli`\n\n``` shell\n\npub global active faraday\n\n# print version\nfaraday version\n\n```\n\n- 准备文件服务器\n\n为了无感集成flutter模块至现有的ios和android工程，需要一个所有团队成员均可访问的文件服务器(支持文件上传下载)来存储编译产物(`ios`为`cocoapods framework`，`android` 为`maven`仓库)\n\u003e 如果暂时没有文件服务器可以下载 [simple-http-server.py](tools/http-server/simple-http-server.py)启动一个用于测试的文件服务器。需要安装`python3`\n\n- cocoapods private spec\n\nios选择使用`cocoapods`来集成，为了让native开的同学无感我们需要创建私有`repo`。\n具体步骤参见 [Private Pods](https://guides.cocoapods.org/making/private-cocoapods.html)\n\n### 配置文件\n\n- *ios native* 项目中添加2个空文件\n\n\u003e 新建2个空文件用来生成 桥接方法和路由 的模版代码，建议文件名 FaradayCommon.swift、FaradayRoute.swift\n\n- *android native* 项目中添加2个空文件\n\n\u003e 建议文件名 FaradayCommon.kt、FaradayRoute.kt\n\n- *flutter module* 项目根目录下创建`.faraday.json`文件\n\n`cli`主要作用就是为ios和android生成模版代码，所以在一切工作开始之前我们需先告诉`cli`相应文件的具体位置。\n\n``` json\n{\n  \"ios-common\": \"/path/to/FaradayCommon.swift\", // 上面2步新建的文件路径\n  \"ios-route\": \"/path/to/FaradayRoute.swift\",\n  \"android-common\": \"/path/to/FaradayCommon.kt\",\n  \"android-route\": \"/path/to/FaradayRoute.kt\"\n}\n\n```\n\n\u003e 版本控制工具请忽略此文件\n\u003e 每个开发者的 `.faraday.json` 文件都需要根据自己的需要配置添加\n\n- `pubspec.yaml`\n\n修改`flutter module`项目下的`pubspec.yaml`文件， 添加以下配置\n\n``` yaml\n\n...\n\nversion: 0.2.1-dev.0\n\n####################################################\nfaraday:\n  static_file_server_address: \"http://localhost:8000\" # 前置条件中的静态文件服务器\n  pod_repo_name: \"faraday\" # 前置条件中的 private pod spec name\n####################################################\n\nenvironment:\n  sdk: \"\u003e=2.9.0 \u003c3.0.0\"\n\n...\n\n```\n\n### 初始化\n\n``` shell\n\ncd [your_flutter_module]\n\nfaraday init\n\n```\n\n初始化完成以后查看`lib/src/debug`目录\n\n![debug_folder](images/debug_folder.png)\n\n同时在`lib/src/`目录下会生成`routes.dart`文件，用来定义flutter侧的路由定义。如果一切正常说明初始化正常\n\n### 集成\n\n初始化完成以后，我们分别在3端来集成faraday\n\n#### flutter\n\n``` dart\nimport 'src/debug/debug.dart';\nimport 'src/routes.dart';\n\n....\n\n// debugMessage 每次打包都会更新称最新版本号，可以添加一个banner显示\ndebugPrint(debugMessage);\n\n// 可以使用 CupertinoApp、MaterialApp、WidgetsApp 或者 Navigator 均可\nCupertinoApp(onGenerateRoute: (_) =\u003e faraday.wrapper(routeFactory));\n\n```\n\niOS端产物说明\n\n- `protocol FaradayCommonHandler { }`\n\n\u003e 自动根据flutter端的common方法定义来生成接口定义，我们需要实现他，一般可以直接用 AppDelegate 实现\n\u003e\n\u003e ``` swift\n\u003e extension AppDelegate: FaradayCommonHandler {\n\u003e ...\n\u003e }\n\u003e ```\n\n- `enum FaradayRoute { }`\n\n\u003e 根据flutter端的路由信息来生成对应的枚举 使用方式 大概如下\n\u003e\n\u003e ``` swift\n\u003e let vc = FaradayRoute.demoPage.viewController()\n\u003e navigationController?.push(viewController: vc)\n\u003e ...\n\u003e }\n\u003e ```\n\nandroid和iOS类似这里就不在赘述\n\n### 添加一个桥接方法\n\n`g_faraday`提供了2个注解`@common`和`@ignore`。当一个类被`@common`注解时，这个类中所包含的所有符合条件的方法都会在`native`侧生成相应的接口类\n\n\u003e 何为符合条件的方法\n\u003e 如果一个方法为 静态方法而且参数和返回值都可以序列化成json，那么就是一个符合条件的方法\n\u003e 如果一个符合条件的方法，不需要生成native接口，那么只需要用`@ignore`注解此方法即可\n\n执行下面的命令，应该可以看到对应的文件生成了相应的方法\n\n``` shell\n\ncd [your_flutter_module]\n\nfaraday generate\n\n```\n\n### 添加一个路由\n\n当一个flutter页面需要从native打开是需要以下两步来操作\n\n- 用`@entry`注解你当前页面的class\n\n- 添加`faraday`静态方法\n\n``` dart\n\n// 声明路由\n\n@entry\nclass DemoPage extends StatefulWidget {\n\n    static Route faraday(int id) =\u003e CupertinoPageRoute(\n        builder: (ctx) =\u003e DemoPage(status),\n      );\n\n    ....\n}\n\n```\n\n执行\n\n``` shell\n\nfaraday generate\n\n```\n\n在对应的`route`文件和`routes.dart`文件中，会根据`faraday`方法的签名，自动生成对应路由\n\n\u003e 如果有路由只需要生成`flutter`侧，不需要从native打开，那么可以考虑使用`@flutterEntry`进行注解\n\n### 打包发布\n\nfaraday对`flutter build`命令进行封装，可以用以下命令快速打包发布\n\n``` shell\n\nfaraday tag --no-release\n\n```\n\n## FAQ\n1. 如何选择faraday版本？\n\u003e根据Module项目是否支持null-safety分为两种情况\n\u003e\n\u003e1. 不支持null-safety, 请使用版本1.2.7, 后续版本将不再维护非null-safety的项目\n\u003e\n\u003e2. 支持null-safety, 请使用版本2.0.7及以上版本，需要dart version 2.15.1及以上版本，该版本dart对应flutter版本为2.8.1\n\n## LICENSE\n\nfaraday_cli is released under the MIT license. [See LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgfaraday%2Fcli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgfaraday%2Fcli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgfaraday%2Fcli/lists"}