草庐IT

用Flutter写了个博客园APP

xiaoyaocz 2023-03-28 原文

最近在摸鱼时看到了一些博客园API文章,就想着摸鱼时写个APP练练手。

现阶段实现了以下功能模块:

  • 博客浏览、评论
  • 新闻浏览
  • 闪存浏览、发布、评论
  • 博问浏览
  • 用户登录

博问暂时只支持浏览,不支持回答提问等操作。

支持iOS、Android平台。

截图

浅色模式:

深色模式:

API

开发前需要先到https://api.cnblogs.com/申请API KEY,申请通过才能使用博客园的API。

输入一下个人信息跟应用信息,提交后等待博客园的审核。通过审核后会收到一封包含ClientId和ClientSecret的邮件。

博客园API文档上的API不全,有些API需要到Github中查询。

开发

API申请完成就可以愉快的进行开发了。
Flutter版本这次选择了最新的3.3,基于GetX框架+Dio来开发,不得不说GetX一把梭的感觉是真的爽。

目录结构跟GetX框架差不多,按我自己的习惯进行了一些改动:

  • app 一些通用的类及样式
  • services 提供数据存储等服务
  • requests 请求的封装
  • generated 生成的国际化文件,使用 get generate locales生成
  • modules 模块,每个会有两个文件,view及controller
  • widgets 自定义的小组件
  • routes 路由定义
  • models 实体类

个人练手项目就加上了一些以前没用过包跟特性体验一下(如lottie、getx国际化)。

这个项目比较简单,技术上没什么好说的,主要说下博文的展示:

博文展示

博文由于是HTML富文本且有一些复杂样式,把文章内容转为Flutter Widget显示的体验挺差,所以还是使用WebView来展示。

在这里我选择了flutter_inappwebview包,这个包会比官方的webview_flutter功能更加丰富,更新也更频繁。

HTML加载流程如下:

  1. 在assets中添加HTML,预留内容、js、css槽位
  2. 在assets中添加两个css样式,分别对应浅色模式及深色模式;css内容可以从任意文章的Web页面抓取
  3. 在assets中添加JS,编写WebView与APP的交互
  4. 在assets中添加highlight.js,实现代码的高亮
  5. 将js、css填充至HTML,css需要根据APP主题选择
  6. 通过API读取博文内容,并填充到HTML中
  7. 通过webViewController.loadData(data: html)在APP中显示博文

具体实现可以看源代码。实现效果:

由于项目依赖WebView(文章、登录),所以只支持iOS、Android平台。要支持其他平台也不难,只需要把文章内容转为Flutter Widget显示再更改下登录逻辑即可。

自动打包

使用Github Actions可以很简单的自动完成打包发布的步骤。

关于Github Actions的介绍,可以看下官方文档

在项目创建根目录创建一个.github/workflows,然后创建一个xxxx.yml,写入以下代码。

name: app-build-action
#推送Tag时触发
on:
  push:
    tags:
      - "*"
jobs:
  build-ios-android:
    # 使用macOS镜像,如果不需要打包iOS,可以替换成Ubuntu
    runs-on: macos-latest
    permissions:
      contents: write
    steps:
      #签出代码 
      - uses: actions/checkout@v2
        with:
          ref: master
       #写出ENV文件
      - name: Create .env
        run: |
          echo "CLIENT_ID=${{ secrets.CLIENT_ID }}" > .env
          echo "CLIENT_SECRET=${{ secrets.CLIENT_SECRET }}" >> .env
      #APK签名设置
      - name: Download Android keystore
        id: android_keystore
        uses: timheuer/base64-to-file@v1.2
        with:
          fileName: keystore.jks
          encodedString: ${{ secrets.KEYSTORE_BASE64 }}
      - name: Create key.properties
        run: |
          echo "storeFile=${{ steps.android_keystore.outputs.filePath }}" > android/key.properties
          echo "storePassword=${{ secrets.STORE_PASSWORD }}" >> android/key.properties
          echo "keyPassword=${{ secrets.KEY_PASSWORD }}" >> android/key.properties
          echo "keyAlias=${{ secrets.KEY_ALIAS }}" >> android/key.properties
      #设置JAVA环境
      - uses: actions/setup-java@v3
        with:
          distribution: 'zulu'
          java-version: "12.x"
          cache: 'gradle'
      #设置Flutter
      - name: Flutter action
        uses: subosito/flutter-action@v2
        with:
          flutter-version: '3.3.9'
          cache: true 
      - name: Restore packages
        run: flutter pub get
      #打包APK
      - name: Build APK
        run: flutter build apk --release
      #上传APK至Artifacts
      - name: Upload APK to Artifacts
        uses: actions/upload-artifact@v3
        with:
          name: app-release.apk
          path: |
            build/app/outputs/flutter-apk/app-release.apk
      #打包iOS
      - name: Build IPA
        run: flutter build ios --release --no-codesign
      #创建未签名ipa
      - name: Create IPA
        run: |
          mkdir build/ios/iphoneos/Payload
          cp -R build/ios/iphoneos/Runner.app build/ios/iphoneos/Payload/Runner.app
          cd build/ios/iphoneos/
          zip -q -r ios_no_sign.ipa Payload
          cd ../../..
      #上传IPA至Artifacts
      - name: Upload IPA to Artifacts
        uses: actions/upload-artifact@v3
        with:
          name: ios_no_sign.ipa
          path: |
            build/ios/iphoneos/ios_no_sign.ipa
      #从document/new_version.json读取版本信息
      - name: Read version
        id: version
        uses: juliangruber/read-file-action@v1
        with:
          path: document/new_version.json
      - name: Echo version
        run: echo "${{ fromJson(steps.version.outputs.content).version }}"
      - name: Echo version content
        run: echo "${{ fromJson(steps.version.outputs.content).version_desc }}"
      #发布至Github Release
      - name: Upload Release
        uses: ncipollo/release-action@v1
        with:
          allowUpdates: true
          artifactErrorsFailBuild: true
          artifacts: "build/app/outputs/flutter-apk/app-release.apk,build/ios/iphoneos/ios_no_sign.ipa"
          name: "${{ fromJson(steps.version.outputs.content).version }}"
          body: "${{ fromJson(steps.version.outputs.content).version_desc }}"
          token: ${{ secrets.TOKEN }}
      #完成
      - run: echo "? This job's status is ${{ job.status }}."

运行脚本前,需要先到Github项目设置-Secrets-Actions中添加以下字段

CLIENT_ID 博客园API ClientId
CLIENT_SECRET 博客园API ClientSecret
KEYSTORE_BASE64 APK签名文件,转为BASE64
KEY_ALIAS APK签名keyAlias
KEY_PASSWORD APK签名keyPassword
STORE_PASSWORD APK签名storePassword
TOKEN Github Token

Github Token点这里添加,注意需要权限的设置。

设置完成后,当想要打包一个新版本时,只需要提交代码并打上Tag推送至Github,即可自动打包。

总结

这个项目没啥难度且博客园API文档还是比较全面,基本对着API做个UI就行了。

天冷变懒了,有些功能还没有写完,过段时间再慢慢完善了。

项目开源地址:https://github.com/xiaoyaocz/flutter_cnblogs,有兴趣可以到Release中下载安装包体验一下。

有关用Flutter写了个博客园APP的更多相关文章

  1. ruby-on-rails - 每次我尝试部署时,我都会得到 - (gcloud.preview.app.deploy) 错误响应 : [4] DEADLINE_EXCEEDED - 2

    我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie

  2. ruby-on-rails - 如何重命名或移动 Rails 的 README_FOR_APP - 2

    当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?

  3. ruby - 使用 postgres.app 在 rvm 下要求 pg 时出错 - 2

    我正在使用Postgres.app在OSX(10.8.3)上。我已经修改了我的PATH,以便应用程序的bin文件夹位于所有其他文件夹之前。Rammy:~phrogz$whichpg_config/Applications/Postgres.app/Contents/MacOS/bin/pg_config我已经安装了rvm并且可以毫无错误地安装pggem,但是当我需要它时我得到一个错误:Rammy:~phrogz$gem-v1.8.25Rammy:~phrogz$geminstallpgFetching:pg-0.15.1.gem(100%)Buildingnativeextension

  4. ruby - 为 capybara 设置 app_host 的内容 - 2

    我的测试尝试访问网页并验证页面上是否存在某些元素。例如,它访问http://foo.com/homepage.html并检查Logo图像,然后访问http://bar.com/store/blah.html并检查页面上是否出现了某些文本。我的目标是访问经过Kerberos身份验证的网页。我发现Kerberos代码如下:主文件uri=URI.parse(Capybara.app_host)kerberos=Kerberos.new(uri.host)@kerberos_token=kerberos.encoded_tokenkerberos.rb文件classKerberosdefini

  5. ruby - 导轨 3 : Creating app with internal plugin system - 2

    我想在Rails中使用插件系统创建一个应用程序。潜在用户应该能够上传(或更好地从存储库安装)一个插件并安装它,使我的应用程序能够做更多的事情。这应该在没有FTP/SSH/对服务器的任何低级别访问的情况下完成。关于如何在Rails3中完成它,是否有任何好的gems或教程? 最佳答案 你看过http://edgeguides.rubyonrails.org/plugins.html了吗??它似乎不是100%兼容Rails3,但它可以帮助您入门。我看过的大多数插件文章都涉及Rails2。 关于

  6. ruby - 使用 Foreman 启动位于不同目录的 Rack App - 2

    我有一个成功运行多个进程的Procfile设置:#/Procfileredis:bundleexecredis-serversidekiq:bundleexecsidekiq-v-C./config.ymlforward:forward4567mock-api我需要再添加一个进程-一个位于我机器上不同目录中的Sinatra应用程序。如果我cd到该目录,我可以从终端启动它:$rackup-p4567我可以使用终端从不同的目录启动它:$sh-c'cd/Path/to/project/&&execrackup-p4567'但是我应该如何使用工头来做到这一点。我尝试添加以下内容,但它无声地失败

  7. Flutter 环境变量配置和flutter doctor中的错误解决 - 2

    一、环境变量右键点击我的电脑-属性:然后找到环境变量 1.Android的SDK不在C盘的话需要额外配这个到用户环境变量:ANDROID_HOMED:\AndroidSDK2.然后在系统变量:Path中添加一条这样的值        D:\Flutter\flutter\bin             这个值写flutter包解压的实际地址即可 3.在系统变量中添加两个镜像变量:        变量名:FLUTTER_STORAGE_BASE_URL      变量值:https://storage.flutter-io.cn        变量名:PUB_HOSTED_URL      变量

  8. ruby - 在 Middleman 中移动博客文章位置 - 2

    我正在为我的网站使用MiddlemanBloggem,但默认情况下,博客文章似乎需要位于/source中,这在查看vim中的树时并不是特别好并尝试在其中找到其他文件之一(例如模板)。通过查看文档,我看不出是否有任何方法可以移动博客文章,以便将它们存储在其他地方,例如blog_articles文件夹或类似文件夹。这可能吗? 最佳答案 将以下内容放入您的config.rb文件中。activate:blogdo|blog|blog.permalink=":year-:month-:day-:title.html"blog.sources=

  9. ruby-on-rails - Rake 文档 :app fails after upgrading to Ruby 2. 1.1 和 Rails 4.1 - 2

    我使用命令rakedoc:app为我的Rails应用程序生成一些基本文档。它在过去一直运行良好。昨天我通过应用程序从Ruby1.9.3升级到2.1.1,从Rails3.2升级到4.1。该应用程序一切正常,所以几周后我第一次重新生成文档,但失败了。我运行上面的命令并收到以下错误消息:rakeaborted!Don'tknowhowtobuildtask'README.rdoc'/home/vagrant/.rvm/gems/ruby-2.1.1/bin/ruby_executable_hooks:15:in`eval'/home/vagrant/.rvm/gems/ruby-2.1.1/

  10. ruby-on-rails - rails : Omniauth - "The parameter app_id is required" - 2

    我正在按照这个railscast教程在我的rails项目上为facebook身份验证设置omniauth:http://railscasts.com/episodes/360-facebook-authentication?autoplay=true.我只用了4分钟,到目前为止我所做的就是捆绑gemomniauth-facebook并添加,omniauth.rbOmniAuth.config.logger=Rails.loggerRails.application.config.middleware.useOmniAuth::Builderdoprovider:facebook,ENV

随机推荐