目标是提出一种保护您的QML代码免受抄袭的方法 . 这是一个问题,因为在这方面,QML的设计和实施方式似乎莫名其妙地不受保护 . 唯一受到保护的QML类型是完全用C实现的类型 .
-
Qt资源文件不支持任何程度的保护
-
即使您压缩资源文件,从中提取数据对于经验适中的人来说仍然是相当微不足道的
-
存储在文件系统上的QML文件几乎可以用于获取
-
同样适用于任何远程QML文件,除了增加对互联网连接的依赖之外,很容易嗅到网络访问并通过他们的网址获取QML文件
-
QML似乎没有提供任何公共API,以允许用户足够的控制QML类型解析来保护他们的代码
总而言之,它几乎看起来Qt故意吝啬QML代码保护,一个明显的候选理由是迫使人们购买具有QML编译器的疯狂表达的商业许可证 .
因此,如果没有任何保护QML源的库存方法,目前我想到的唯一解决方案是控制如何解决QML类型 . 有几种方法可以将类型注册到QML:
-
在应用程序可执行文件中注册
-
在插件中注册
-
通过QML模块注册
但是,我需要的是手动解析QML类型,就像你可以创建一个输入URL字符串并输出图像的自定义 QQuickImageProvider
,我需要QML引擎来请求一个字符串,其类型为我的自定义组件提供程序,它输出一个准备好对象实例化组件 .
如果使用任何自定义实例化机制,这将很容易,但我需要这些类型在常规QML源中可用 . 理想情况下,在查看可用的导入路径或甚至是内部注册的类型之前,这应该是用于解析类型的第一种机制 .
或者,如果有一种方法可以完全用C语言定义QML模块,没有任何外部QML文件,没有 qmldir
文件等,那将同样有用 .
作为最后的手段,理想情况下,我还倾向于将QML(非C)类型注册到运行时,这也可能有用,但我更愿意完全控制解析过程 .
QML插件没有这个技巧,因为它注册了C类型,我想注册QML类型,即从字符串源创建并相互引用的 QQmlComponent
.
3 回答
(理想)解决方案:预编译它
Qt Quick Compiler是Qt Quick应用程序的开发附件,允许您将QML源代码编译为最终二进制文件 . As it's description says,它将有助于防止剽窃,它还可以增强您的应用程序启动时间并提供其他好处 .
This is as close as you can get to protecting your QML source code, even when it's not yet fully optimized
更新
从Qt 5.11开始,解决方案已经到位并且变得更快 .
更新(2)
Seems the QML compiler is already opensource from 5.11我无法讲述工具,但Lars Knoll在博客文章中解释了这一点 .
选项A)使用qtquick编译器
选项B)使用加密资源:
将资源编译成单独的文件:rcc -binary your_resource.qrc -o extresources.rcc
将extresources.rcc加密到extresources.rcc.cr(例如使用gnupg)
创建一个新的资源文件APP.rcc,仅使用extresources.rcc.cr文件
启动时,加载“:/extresources.rcc.cr”并将它们解密到缓冲区(你需要一个像Libgcrypt这样的加密库...隐藏反编译器和调试器的私钥等)
Q_CLEANUP_RESOURCE(APP); (可选,清除APP.rcc以节省内存)
Resource :: registerResource((unsigned char *)myBuffer.constData()))
//现在,你有可用的解密资源......例如
engine.load(QUrl( “QRC:/main.qml”))
真正的实现并非无足轻重,但效果非常好......
经过一番挖掘后,我找到了两个可能值得追求的方向:
使用自定义
QQmlAbstractUrlInterceptor
用于QML引擎,解析QML类型并重新编号QUrl
,在"protected"类型的情况下,拦截器可以预先添加自定义方案 . 使用自定义QNetworkAccessManager
拦截该URL,调用未受保护类型的默认实现,对于受保护类型,解密数据并将其返回QNetworkReply
.另一个更简单但不太灵活的解决方案只涉及第二部分以前的解决方案,以及
qmlRegisterType(const QUrl &url, ...)
函数公开为QML类型,避免使用拦截器 .我会在调查这两个时发布更新 . 请注意,这也不是100%安全,因为使用解密代码本身的网络回复将至少暂时保留在RAM中,因此如果有足够的能力,仍然可以获得代码,但是它并不像访问代码那样微不足道 . 它直接来自应用程序二进制文件更进一步的可能方向是求助于不包含解密数据的自定义
QNetworkReply
,但重载QIODevice
部分作为加密数据的访问者,在读取它的过程中对其进行解密 .