众所不周知,在大概 3 4 年前曾经有这么一个项目叫 sona
,这是一个音乐播放器,react native
,连着网抑云。大概长这样
过了这么久,我早就不网抑云,也以现在的眼光再看这个 UI 未免有些稚气,还有点费电资源 —— 整的什么垃圾
正好,关注了一年多的 MAUI
,纯纯在 Build 看着宣布,然后 GitHub 开库,进 preview,到现在 stable。.NET 都从 6 preview 一直到 7…
所以先来搂一眼,正好也想复活这个产品,并且不优先解决网抑云,而是解决 Apple Music 和 Spotify,还有 Last.fm。再决定是改用 maui 重构还是继续用 RN
TL;DR
- C# 很香,但遗传了 Xamarin 的臭
- 安卓 SDK 两个包,噶了一个
- 平台能力最好还是用平台原生语言
- 目前的 MAUI,狗都不用
MAUI
一句话:MAUI 是另一个 React Native 但 C#,不是 Flutter
MAUI 前面有 Xamarin
(分平台的不是 Xamarin.Forms
),服就服在微软能把各个平台的 API 都转一份,这样所有代码都使用 C# 编写,以便享受这个极其变态的编译器。当你创建一个 mac 的 Xamarin 应用,你会发现除了语法是 C#,无论结构还是文件组织都与直接用 XCode 创建出来的项目不能说有点相似,只能说完全一致
高情商:令人钦佩的软件工程能力;低情商:吃饱了撑着
所以作为后继者,MAUI 在平台调用依然会是全 C#,不像 flutter 或者 RN 在分别平台使用 swift/kotlin。这样有好坏
好是因为全 C#,在编写平台逻辑时可以直接使用通用的 interface
,或者是 common 写一个 partial
,再分平台补充实现。即使在通用代码也可以用 macro 来区分平台生成代码,毕竟不用担心,编译会根据编译目标选择源代码
坏那也坏,RN 和 flutter 的方式是让平台代码完全使用平台程序,相当于写了一个原生程序,通过桥通信交换信息,这样可以保证平台逻辑是绝对的平台逻辑,《非常原生》。而反过来就是 MAUI 的缺点,谁也不知道到底这个翻译官水平如何
MusicKit
WWDC21 宣布了 MusicKit
,WWDC22 宣布了其他平台的 MusicKit SDK 和 Apple Music API,至此 Apple Music 可以在其他平台集成,包括 Web
只不过,据我所知,Apple Music API 和 MusicKit Web 只有很普通的音质,没有 ALAC,没有 Dolby Atmos,其实后者没有应该不奇怪
Combine
按照平台分,方案如下:
- iOS/iPadOS:系统带着了,直接写,可以参考 Xamarin.iOS 的示例
- Android: 使用官方 SDK,一共两个 aar
- 其他:只能封装 Apple Music API
这个项目在 RN 的时候也仅考虑 iOS 和 Android。这次会考虑新增 iPad 和桌面端,但无所谓
Create Library(s)
如果按照 React Native 的习惯,可能会创建一个插件项目,接着分别在对应位置做平台实现。但,Xamarin
似乎不是这么做的
首先需要创建两个 Binding 项目:Android Bindings Library
和 iOS Bindings Library
毕竟只是概念验证,所以这次不实现 iOS,先试试 aar
绑定。这里可以参考微软文档 Binding an .AAR
在安卓,Apple Music 提供了两个 arr
:
- mediaplayback:Apple Music 部分,用于获取专辑,音乐信息等
- musickitauth: MusicKit 的验证部分(例如直接使用本地的 Apple Music 进行授权,类似通过 QQ 登录)
一个一个来
Droid.MusicKit - mediaplayback
(似乎 Xamarin 的插件大火都是这么命名的)
先处理 mediaplayback,按照文档,创建项目之后,把 aar
直接拖进项目,并设置「生成操作设置」
- 将 textanalyzer.aar 的生成操作设置为 LibraryProjectZip
Xamarin 虽然是这么设置的,但是在 Visual Studio 2022 已经没有这个选项了,取而代之的是 AndroidLibrary
然后就可以开始生成了,要不怎么说微软 nb 呢 —— .NET 会解析 arr
或者 jar
,将所有签名或者代码结构生成出来,并以类为单位生成一个个 C# 文件,作为 header file 使用
但,刚说什么来着?
谁也不知道到底这个翻译官水平如何
不出意外的话马上又要出意外了
寄!
mediaplayback 关于音乐部分是原生库(.so),应该是 JNI 部分依赖了 javacpp
,而 javacpp
在翻译成 C# 的时候出问题了。尝试解决一下但无法解决,想抄作业全网搜索没有一个相似案例可以抄作业。如果直接用 kotlin 我会受这苦?
没办法只能退而求其次 —— 本地授权完获取 token 之后,剩下的走 Apple Music API。但即使可以的话,音质可能是收音机水平
Droid.MusicKit - musickitauth
跟 mediaplayback 一样,把 arr 拖进来,改成 AndroidLibrary
之后编译,很意外的非常顺利,只有几百个警告。在老程序员的眼里,1000 个警告都是无异常
接着,在 MAUI 的项目中打开「引用」目录,右键这个目录添加引用,把 Droid.MusicKit
添加进来,再编译一遍。没有报错的话就是没有报错
要不怎么说微软 nb 呢x2,在使用时,可以直接 using 包名
using Com.Apple.Android.Sdk.Authentication;
这里采用的方式是:先在公用逻辑写一半类,接着在对应的平台实现里完成各个平台调用
namespace MauiDemo.Services
{
public partial class MusicKitService
{
public partial void Auth();
}
}
接着到 android 目录,创建一个 MusicKitService.cs
namespace MauiDemo.Services
{
public partial class MusicKitService
{
public partial void Auth()
{
// 当前 activity(如果有更好的方式的话欢迎告诉我)
var activity = Microsoft.Maui.ApplicationModel.Platform.CurrentActivity;
// 应用上下文(React Native 直接在 props 进来的那个)
var context = Android.App.Application.Context;
var authenticationManager = AuthenticationFactory.CreateAuthenticationManager(context);
var developerToken = "";
var intent = authenticationManager
.CreateIntentBuilder(developerToken)
.SetHideStartScreen(false)
// 授权页面显示的告示信息
.SetStartScreenMessage("要想听歌就赶紧授权!")
.Build();
// 跳转 activity(android 原生应该很熟悉)
activity.StartActivityForResult(intent, 100);
}
}
}
最后随便绑定到项目创建时的 Demo 的按钮上,不出意外的话点击按钮就能显示 Apple Music 的授权页面(跳转到 Apple Music 或者让你安装一个)
总结
零零散散写了很久,文章周期很长。可能有上文不接下气的感觉
本来对 MAUI 寄予厚望,现在理性考虑还是不会使用
一方面是需要踩坑的地方目测得到的就有点多(如果之前没踩过 Xamarin 的话还得算上);一方面目前社区不活跃,有点冷门的实现自己搞不定
体感上会比印象中的 React Native 好很多(新解释器和 Hermes 还没用过),但开发成本和理解成本不在一个层面
总之,看还是会看,暗中观察。用的话现在不会用(但是体感上 Xamarin 真的要比 React Native 好,很纠结…