我用 Flutter 开发并上线了一款微信小游戏 - 小周五子棋

3,366 阅读5分钟

废话少说,上小程序码,大家可以先体验一下。

image.png

一、Flutter开发小程序想法的由来

大家好,我是移动端开发工程师小周,最近我上班的公司提出一个新需求,要求把公司产品的 移动端 APP 的所有查看功能在移植到小程序,而且时间限制在半个月 ,这可把我难住了,虽然只是查看的功能,但是也有几十个页面,而且之前都是用 Flutter 开发的。

直接用小程序开发是不敢想的,一来小程序开发不熟练,二来开发时间有限,而且UI组件都是定制的。所以我的第一想法是将 Flutter 打包成 Web 端代码,然后使用小程序的 WebView 加载,电脑浏览器运行还能接受,结果发现小程序的 WebView自带顶部导航栏且不可隐藏 ,而且 兼容性问题很多,且性能很差,运行很卡

也许是上天眷顾,我无意间在微信公众号上看到了一篇文章,刚好就是说如何将 Flutter 代码转成小程序代码的,点进去看了,使用的是一个小程序开发框架: MpFlutter

image.png

我在接入过程中遇到了很多问题,比如文件大小限制、包大小限制、卡顿等问题,联系开发者 PonyCui 之后,都一一耐心解决了,最终小程序如期上线。

二、Flutter开发小游戏想法的由来

之前一直对小游戏开发比较好奇,于是研究了一下游戏如何开发,试用了 Cocos 等引擎,觉得开发工具很不习惯,且无从下手。

刚好发现 MpFlutter 也支持打包成微信小游戏,于是在咨询了 PonyCui 之后,决定使用 MpFlutter 开发一款小游戏。

三、开发流程

先根据 MpFlutter官方文档 , 接入 MpFlutter 到项目里。

然后照常编写 Flutter 代码即可。

这里浅浅说一下开发五子棋的一些难点:

  1. 棋盘缩放(双指缩放/拖动棋盘)
  2. 滑动落子(拖动或点击落子)
  3. 延迟落子(读秒/双击落子)
  4. 落子确认(按钮确认落子)
  5. 禁手判断(三三、四四、长连)
  6. AI算法(人机对战)

这里分享一下 棋盘缩放滑动落子 的实现,重点是解决双指和单指的冲突 ,用到了 InteractiveViewerListener 控件。

// 拖拽X坐标
double? dragX;
// 拖拽Y坐标
double? dragY;
// 是否正在缩放
bool isScaling = false;
// 是否正在落子
bool isMoving = false;
// 缩放比例
double scale = 1;
// 是否缩放变化
bool scaleChanged = false;
// 触点数量是否变化
bool pointerChanged = false;
// 上次双指操作时间
int lastTwoPointerTime = 0;
// 触点数量
int pointerCount = 0;

// 重置棋盘缩放
resetScale() {
  setState(() {
    transformationController.value = Matrix4.identity();
  });
}
InteractiveViewer(
  minScale: 1.0,
  panEnabled: false,
  transformationController: transformationController,
  onInteractionUpdate: (details) {
    double newScale = transformationController.value.getMaxScaleOnAxis();
    scaleChanged = scale != newScale;
    pointerCount = details.pointerCount;
    if (details.pointerCount > 1) {
      lastTwoPointerTime = Tools.currentTimeMillis();
      dragX = null;
      dragY = null;
    }
    if (pointerChanged) {
      dragX = null;
      dragY = null;
    }
  },
  onInteractionEnd: (details) async {
    if (details.pointerCount > 0 &&
        pointerCount != details.pointerCount) {
      pointerChanged = true;
    }
    scale = transformationController.value.getMaxScaleOnAxis();
    pointerCount = details.pointerCount;
    if (!scaleChanged &&
        Tools.currentTimeMillis() - lastTwoPointerTime > 100 &&
        dragX != null &&
        dragY != null &&
        pointerCount <= 1 &&
        !pointerChanged) {
      // 没缩放,落子
      Chess? chess = _findChessOfPosition(dragX! + 13.r, dragY! + 13.r);
      setState(() {
        dragX = null;
        dragY = null;
      });
      if (chess != null) {
        // print("触发落子");
        //todo 这里处理落子逻辑
        
      }
    } else {
      setState(() {
        dragX = null;
        dragY = null;
      });
    }
    if (pointerCount == 0) {
      pointerChanged = false;
    }
  },
  child: Listener(
    onPointerCancel: (details) {
      setState(() {
        dragX = null;
        dragY = null;
      });
    },
    onPointerDown: (details) {
      dragX = min(max(0, details.localPosition.dx - 13.r), maxX);
      dragY = min(max(details.localPosition.dy - 13.r, 0), maxX);
    },
    onPointerMove: (details) {
      setState(() {
        if (pointerCount <= 1 && !pointerChanged) {
          dragX = min(max(0, details.localPosition.dx - 13.r), maxX);
          dragY = min(max(details.localPosition.dy - 13.r, 0), maxX);
        } else {
          dragX = null;
          dragY = null;
        }
      });
    },
    //todo ... 绘制棋盘  
  ),
)

PC端热重载调试教程

分包教程

构建打包教程

四、注意事项

  • 只能使用纯 dart 的三方库
  • main.dart 文件里尽量少引用库或者使用deferred延迟加载,否则打包出来的js文件过大
  • 加载网络图片 useNativeCodec(url) 包装url
  • 小游戏分享功能需要使用微信api代码动态打开
wx.showShareMenu(ShowShareMenuOption()
  ..withShareTicket = true
  ..menus = ['shareAppMessage', 'shareTimeline']);
  • 监听回到小程序
wx.onShow((p0) async {
  Log.d("onShow");
});
  • 获取启动参数
var enterOptionsSync = wx.getEnterOptionsSync();

五、小游戏上架过程

  1. 微信认证(2天,30元)
  2. 代码编写(2周)
  3. 提交代码审核(审核1周)
  4. 备案四部曲(审核1个半月)

image.png

1. 代码审核小插曲

代码提交上去之后,被拒了,理由是涉嫌和一个叫 全民口算 的小程序代码侵权。

c6ef12be314eaa773f0f1d8ee71066d7(20240417-134040).png

当时我那叫一个冤啊,自己敲出来的代码,哪门子侵权,于是我去社区找找有没有解决方案,发现还有不少同样的情况,但是没有一个给出了明确的解决方案,官方的回答也不好理解。

image.png

其实,最直接的申诉方式,还是在微信公众平台后台小程序审核不通过的通知里,直接点点此反馈,填写申诉理由,不过,这个申诉只有一次机会,我一开始着急没说清楚,申诉没通过。

ea2ce6711a0b551be103443bfdceea36(20240417-165445).png

a0bd3bab091d681f323cd5fcc98f7553.png

后来和 PonyCui 沟通后, PonyCui 给我写了一个 申诉模板 ,然后我去社区发了帖子,但是没任何回应,最后,添加了小程序官方助手(minigame3)的微信,得知现在都是通过 企业微信服务号 解决问题,然后在服务号上也发了申诉内容,不过服务号也是相当于留言形式,不会立即回复。

因此,我也没有闲着,我又去后台提交了一个小游戏版本,在版本更新说明里,放上了申诉说明,并附上了部分源代码的github链接。

最后,代码审核通过了。

image.png

2. 游戏内容介绍小插曲

游戏内容介绍里需要提供十几张截图,而且每一张图片都不能重复,一开始我就用了好几张重复图片,导致一直被打回,检测图片重复应该是机器审核,打回很快。

六、总结

这是我开发的第一款小游戏,之前也开发过几款小程序,发现小游戏的审核和上架过程比小程序要麻烦很多,审核时间也长很多,不过后续小游戏的运营和用户量才是一大挑战,希望好心人可以帮我转发一下文章(感谢♪(・ω・)ノ),也能吸引一些用户。

最后,非常感谢在这个过程中耐心帮助我的 PonyCui ,大家也可以参考我的总结,尝试用 MpFlutter 做一个自己的小程序或者小游戏,相信你一定会打开一个新世界的大门,并且在这个过程中收获满满。