<?xml version="1.0" encoding="utf-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>YLong软件</title><link>https://www.ylongsoft.com/</link><description>网址打包APP, 全景KRPano可是化编辑器, IOS重签名加密工具</description><item><title>安卓手机更新WebView内核全攻略</title><link>https://www.ylongsoft.com/post/android-webview-update-guide.html</link><description>&lt;p&gt;安卓APP内嵌的网页，并非由APP自身渲染，而是依赖系统组件——&lt;strong&gt;WebView&lt;/strong&gt;。它相当于手机内置的通用“浏览器引擎”，所有需要显示网页的APP（包括通过HTML一键打包APK工具生成的APP）都共享使用该组件。&lt;/p&gt;
&lt;p&gt;HTML一键打包APK工具为了控制APK体积，默认调用系统WebView来渲染页面，而非将完整浏览器内核打包到应用中。这导致了一个常见现象：&lt;strong&gt;相同的页面，在不同手机上表现迥异——一台显示正常，另一台可能布局错乱或功能失效&lt;/strong&gt;，其根源往往在于系统WebView版本不一致。&lt;/p&gt;
&lt;p&gt;当你的APP在特定手机上出现样式异常、新特性无法使用、视频或页面无法加载，而切换另一台设备却一切正常时，优先检查的是该手机的WebView版本，而非打包配置。&lt;/p&gt;
&lt;p&gt;如果你对HTML打包APK工具还不熟悉，可访问官网了解详情：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://leapever.com/intro/apk-packer&quot;&gt;HTML一键打包APK工具官网&lt;/a&gt;&lt;/p&gt;
&lt;!-- truncate --&gt;
&lt;h2&gt;WebView版本为何至关重要&lt;/h2&gt;
&lt;p&gt;WebView版本直接决定了APP能够支持哪些网页标准。版本越新，支持的HTML、CSS和JavaScript特性越丰富。&lt;/p&gt;
&lt;p&gt;若版本过旧，常见问题包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;较新的CSS特性（如 &lt;code&gt;:has()&lt;/code&gt;、容器查询、级联层）无效，导致页面布局错位&lt;/li&gt;
&lt;li&gt;较新的JavaScript语法（可选链、空值合并、顶层 &lt;code&gt;await&lt;/code&gt; 等）抛出错误，脚本整体失效&lt;/li&gt;
&lt;li&gt;部分视频和音频编码无法解码，出现仅有声音而无画面&lt;/li&gt;
&lt;li&gt;新版API（如全屏、剪贴板、文件系统访问）缺失，点击功能无响应&lt;/li&gt;
&lt;li&gt;安全策略差异导致HTTPS资源被意外拦截&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;反之，将系统WebView更新至最新版，上述问题通常无需修改代码即可解决。&lt;/p&gt;
&lt;h2&gt;查询当前WebView版本的方法&lt;/h2&gt;
&lt;p&gt;问题排查前，先确认手机当前的WebView版本。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;方法一：通过系统设置&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开手机&lt;strong&gt;设置&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;在顶部搜索栏输入 &lt;strong&gt;WebView&lt;/strong&gt; 或 &lt;strong&gt;Android System WebView&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;点击 &lt;strong&gt;Android System WebView&lt;/strong&gt;（部分机型显示为“系统WebView”），在详情页可查看到版本号。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;方法二：检查WebView实现（安卓7.0及以上）&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;进入&lt;strong&gt;设置 → 关于手机&lt;/strong&gt;，连续点击&lt;strong&gt;版本号&lt;/strong&gt;直至提示进入开发者模式。&lt;/li&gt;
&lt;li&gt;返回设置，进入&lt;strong&gt;系统 → 开发者选项&lt;/strong&gt;（不同品牌位置略有差异，可搜索“WebView”）。&lt;/li&gt;
&lt;li&gt;找到 &lt;strong&gt;WebView实现&lt;/strong&gt;（或“WebView Implementation”），可查看当前使用的是 &lt;strong&gt;Android System WebView&lt;/strong&gt; 还是 &lt;strong&gt;Chrome&lt;/strong&gt;，并支持切换。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;方法三：通过网页检测内核版本&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;使用出问题的APP或手机浏览器打开在线内核检测页面，页面会显示当前内核版本和兼容性评分。对比正常手机与异常手机的检测结果，差异一目了然。&lt;/p&gt;
&lt;h2&gt;通用更新方法（适用于多数机型）&lt;/h2&gt;
&lt;p&gt;在查找特定品牌方法前，可尝试以下三种通用方式，它们能覆盖绝大多数场景。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 更新Android System WebView组件&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;打开手机自带的应用商店（或Google Play），搜索 &lt;strong&gt;Android System WebView&lt;/strong&gt;，若有“更新”按钮，直接更新即可。这是最直接的升级途径。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 更新Chrome浏览器&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在安卓7.0及以上系统中，Chrome可作为WebView的实现者。将Chrome更新至最新版，然后在开发者选项中将WebView实现切换为Chrome，相当于更换了一套更新的内核。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 升级系统版本&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;部分厂商将WebView作为系统组件随系统更新一起推送。若应用商店中搜索不到WebView，可进入&lt;strong&gt;设置 → 系统升级/软件更新&lt;/strong&gt;，将系统更新至最新版，WebView通常会自动升级。&lt;/p&gt;
&lt;h2&gt;各品牌手机专属更新方案&lt;/h2&gt;
&lt;p&gt;不同厂商对WebView的打包和更新策略各有差异，以下按品牌详细说明。&lt;/p&gt;
&lt;h3&gt;华为（HarmonyOS / EMUI）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;打开&lt;strong&gt;华为应用市场&lt;/strong&gt;，搜索 &lt;strong&gt;华为浏览器&lt;/strong&gt;（或“浏览器”），若有更新则更新。华为机型主要由华为浏览器提供系统WebView内核。&lt;/li&gt;
&lt;li&gt;部分支持GMS的机型，可在应用市场或Google Play中搜索 &lt;strong&gt;Android System WebView&lt;/strong&gt; 单独更新。&lt;/li&gt;
&lt;li&gt;亦可进入&lt;strong&gt;设置 → 系统和更新 → 软件更新&lt;/strong&gt;升级系统，内核会随系统更新。&lt;/li&gt;
&lt;li&gt;注意：HarmonyOS NEXT（纯鸿蒙）使用自研内核，仅能通过系统更新和华为浏览器更新获取新特性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;荣耀（MagicOS）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;打开&lt;strong&gt;荣耀应用市场&lt;/strong&gt;（或“我的荣耀”），搜索 &lt;strong&gt;荣耀浏览器&lt;/strong&gt; / &lt;strong&gt;Android System WebView&lt;/strong&gt; 进行更新。&lt;/li&gt;
&lt;li&gt;进入&lt;strong&gt;设置 → 系统和更新 → 软件更新&lt;/strong&gt;，检查系统更新。&lt;/li&gt;
&lt;li&gt;安卓7.0以上机型可在开发者选项中切换WebView实现。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;小米 / Redmi（HyperOS / MIUI）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;打开&lt;strong&gt;小米应用商店&lt;/strong&gt;，搜索 &lt;strong&gt;Android System WebView&lt;/strong&gt; 或 &lt;strong&gt;WebView&lt;/strong&gt;，更新即可。&lt;/li&gt;
&lt;li&gt;也可进入&lt;strong&gt;设置 → 我的设备 → 系统版本&lt;/strong&gt;（或“关于本机”）检查系统更新。&lt;/li&gt;
&lt;li&gt;在&lt;strong&gt;设置 → 更多设置 → 开发者选项 → WebView实现&lt;/strong&gt;中，可切换至新版Chrome作为内核。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;OPPO / 一加 / realme（ColorOS / OxygenOS / realme UI）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;打开&lt;strong&gt;软件商店&lt;/strong&gt;，搜索 &lt;strong&gt;Android System WebView&lt;/strong&gt;，更新至最新版。&lt;/li&gt;
&lt;li&gt;进入&lt;strong&gt;设置 → 软件更新&lt;/strong&gt;（ColorOS为“设置 → 关于本机 → 版本信息”）检查系统更新。&lt;/li&gt;
&lt;li&gt;一加海外版机型可直接通过Google Play更新WebView和Chrome。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;vivo / iQOO（OriginOS / Funtouch OS）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;打开&lt;strong&gt;vivo应用商店&lt;/strong&gt;，搜索 &lt;strong&gt;Android System WebView&lt;/strong&gt; 更新。&lt;/li&gt;
&lt;li&gt;进入&lt;strong&gt;设置 → 系统管理 → 系统升级&lt;/strong&gt;（部分版本为“设置 → 系统升级”）更新系统。&lt;/li&gt;
&lt;li&gt;开发者选项中同样可切换WebView实现。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;三星（One UI）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;打开 &lt;strong&gt;Galaxy Store&lt;/strong&gt; 或 &lt;strong&gt;Google Play&lt;/strong&gt;，搜索 &lt;strong&gt;Android System WebView&lt;/strong&gt; 和 &lt;strong&gt;Google Chrome&lt;/strong&gt;，分别更新。&lt;/li&gt;
&lt;li&gt;国行机型可进入&lt;strong&gt;设置 → 软件更新 → 下载并安装&lt;/strong&gt;更新系统。&lt;/li&gt;
&lt;li&gt;三星机型通常同时安装有WebView和Chrome，更新后在开发者选项中切换即可。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;魅族 / 联想 / 中兴 / 传音等其他品牌&lt;/h3&gt;
&lt;p&gt;这些品牌基本采用原生方案：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在自带应用商店搜索 &lt;strong&gt;Android System WebView&lt;/strong&gt; 更新。&lt;/li&gt;
&lt;li&gt;若商店无结果，检查&lt;strong&gt;系统更新&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;若仍无法更新，可安装最新版 &lt;strong&gt;Google Chrome&lt;/strong&gt;，然后在开发者选项中把WebView实现切换为Chrome。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;更新后的操作步骤&lt;/h2&gt;
&lt;p&gt;更新WebView属于系统层面变更，APP本身&lt;strong&gt;无需重新打包&lt;/strong&gt;，也无需重新安装。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;更新完成后，&lt;strong&gt;重启一次手机&lt;/strong&gt;，确保系统加载新内核。&lt;/li&gt;
&lt;li&gt;重新打开APP，验证之前异常的页面是否恢复正常。&lt;/li&gt;
&lt;li&gt;若APP有缓存，可在&lt;strong&gt;设置 → 应用管理&lt;/strong&gt;中找到该APP，清除缓存后再试。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;常见问题解答&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;所有页面都正常，仅有我的APP有问题，也是WebView的原因吗？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;可能性很高。因为手机浏览器（Chrome、华为浏览器等）使用自身完整内核，而APP使用系统WebView组件，两者版本可能不一致。浏览器能打开不代表APP内WebView版本足够新。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用商店搜不到Android System WebView怎么办？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;部分厂商的应用商店不上架该组件。可先尝试系统更新；若系统已是最新，安装最新版Chrome，然后在开发者选项中把WebView实现切换为Chrome，同样能达到升级内核的效果。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;更新WebView会影响手机上的其他APP吗？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;会，但均为正面影响。WebView是系统共享组件，更新后所有使用网页的APP都会受益。通过官方渠道更新是安全的，但切勿安装来路不明的“WebView升级包”APK。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;安卓4.4及以下的旧设备能更新吗？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;不能。独立的WebView更新机制从安卓5.0开始才提供。这类设备只能通过升级整个系统ROM来提高内核版本，建议在页面代码上做好兼容性降级处理。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;更新后APP里仍是老样子，怎么办？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;首先确认开发者选项中的WebView实现指向的是已更新的组件；然后重启手机；最后清除APP缓存再试。若问题依旧，说明可能是页面代码使用了过于激进的特性，建议为目标机型做降级兼容。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;有没有办法不依赖用户手机的WebView版本？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;使用HTML一键打包APK工具时，页面始终由系统WebView渲染，无法随包携带独立内核。因此实际可行的做法是：一是引导用户更新系统WebView，二是在页面中使用成熟、兼容性好的写法，对高级特性做好特性检测与降级方案。&lt;/p&gt;
&lt;h2&gt;实用建议&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;当出现“某台手机上样式错乱或功能失效”时，先对比WebView版本，再排查代码。&lt;/li&gt;
&lt;li&gt;更新WebView优先走官方应用商店和系统更新，不要安装第三方内核包。&lt;/li&gt;
&lt;li&gt;分发APP前，尽量在一台WebView版本较旧的设备上做一次兼容性测试。&lt;/li&gt;
&lt;li&gt;页面开发阶段避免依赖过于新颖的浏览器特性，必要时进行特性检测与降级处理。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;相关文章&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://leapever.com/intro/apk-packer&quot;&gt;HTML一键打包APK工具官网&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://api.leapever.com/apkpacker/download&quot;&gt;立即下载HTML一键打包APK工具&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://leapever.com/tutorial/html-apk-user-agent-setting&quot;&gt;HTML打包APK之User Agent设置教程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://leapever.com/tutorial/html-apk-video-fullscreen-player&quot;&gt;HTML打包APK实现视频播放和全屏播放教程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://leapever.com/tutorial/html-apk-camera-video-audio-file-picker&quot;&gt;HTML打包APK实现拍照、录像、录音和文件选择教程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://leapever.com/tutorial/html-apk-file-download&quot;&gt;HTML打包APK之文件下载功能教程&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description><pubDate>Tue, 01 Sep 2026 19:29:15 +0800</pubDate></item><item><title>C#强签名作用与恒盾混淆大师使用教程</title><link>https://www.ylongsoft.com/post/csharp-strong-name-guide.html</link><description>&lt;p&gt;在使用&lt;a href=&quot;https://csharpobf.leapever.com/&quot;&gt;恒盾C#混淆加密大师&lt;/a&gt;处理 C# DLL 或 EXE 时，如果原始程序集本身已有强名称（Strong Name），混淆后会面临一个问题：原有的强签名失效了。这是因为混淆涉及重命名、流程混淆、字符串加密等操作，这些都会改变文件的二进制内容，而强签名恰恰与二进制内容绑定，任何改动都会导致校验失败。&lt;/p&gt;
&lt;p&gt;软件内置的强签名功能，可以在混淆完成后，用你指定的 .snk 密钥文件对输出程序重新签名。这样，处理后的文件既能享受混淆保护，又能拥有有效的强名称签名，方便其他程序集引用，或安装到全局程序集缓存（GAC）中。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1788181005061_ab80e72a.png&quot; alt=&quot;恒盾C#混淆加密大师强签名配置&quot;&gt;&lt;/p&gt;
&lt;!-- truncate --&gt;
&lt;h2&gt;强签名到底有什么价值&lt;/h2&gt;
&lt;p&gt;强签名是 .NET 框架为程序集提供的一套标识与校验机制，利用一对公私钥（存储在 .snk 文件里）生成数字签名。它的核心价值体现在：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;唯一性标识&lt;/strong&gt;：强名称由程序集名称、版本号、区域性和公钥标记（Public Key Token）构成。不同密钥签名的同名程序集可以共存，避免命名冲突。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;防篡改检测&lt;/strong&gt;：签名与程序集内容绑定，文件被修改后校验失败，可用于识别篡改。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;引用绑定&lt;/strong&gt;：当强签名程序集引用另一个时，运行时会根据“简单名称 + 公钥标记”进行绑定，只有密钥一致才能正常加载。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;需要注意的是，强签名只负责“是谁”和“是否被改”，它不等于加密或混淆，不能替代代码保护功能。两者结合，才能实现“防篡改”与“难反编译”的双重目标。&lt;/p&gt;
&lt;h2&gt;为什么混淆后必须重新签名&lt;/h2&gt;
&lt;p&gt;如果输入的 DLL 或 EXE 本身就是强签名程序集，混淆完成后，内容变了，原签名自然失效。这会引发两个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;引用无法加载&lt;/strong&gt;：其他程序集在编译时记录了强名称引用，签名失效或公钥标记改变后，运行时可能抛出找不到程序集或加载异常。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;签名校验失败&lt;/strong&gt;：在需要签名校验的场景（如 GAC 部署）中，失效的文件会被直接拒绝。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;恒盾的强签名功能，可以用与原始程序集相同的 .snk 密钥重新签名，确保公钥标记不变，延续引用关系。这是启用该功能最常见的原因。&lt;/p&gt;
&lt;p&gt;如果原始程序本来没有强签名，也可以利用这个功能为输出文件补上签名，例如后续需要将 DLL 安装到 GAC，或公司规定要求所有程序集必须签名时。&lt;/p&gt;
&lt;h2&gt;如何生成 .snk 密钥文件&lt;/h2&gt;
&lt;p&gt;强签名需要 .snk 格式的密钥文件。如果项目中已有密钥文件（比如编译时用的 &lt;code&gt;xxx.snk&lt;/code&gt;），直接使用即可。常见生成方式有两种：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;方法一：使用命令行工具&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在 Visual Studio 的“开发者命令提示符”中执行：&lt;/p&gt;
&lt;pre class=&quot;prism-highlight prism-language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;sn -k MyKey.snk
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这会在当前目录生成一个包含公私钥对的密钥文件。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;方法二：使用 Visual Studio 界面&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在传统 .NET Framework 项目中，打开“项目属性” → “签名”页，勾选“为程序集签名”，点击“新建”即可。SDK 风格项目（.NET Core / .NET 5+）也可以在属性中勾选“为程序集生成强名称”来创建。&lt;/p&gt;
&lt;h2&gt;具体配置步骤&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;打开恒盾C#混淆加密大师，切换到“强签名配置”选项卡。&lt;/li&gt;
&lt;li&gt;勾选“启用强签名”，密钥文件输入框变为可用。&lt;/li&gt;
&lt;li&gt;点击“选择文件”，指定用于签名的 .snk 文件。&lt;/li&gt;
&lt;li&gt;回到“快速混淆加密”选项卡，选择要处理的 DLL 或 EXE，按需勾选保护、混淆和重命名等选项。&lt;/li&gt;
&lt;li&gt;设置输出文件路径，点击“开始处理”。&lt;/li&gt;
&lt;li&gt;处理完成后，输出的文件即带有有效强名称签名。&lt;/li&gt;
&lt;li&gt;如需保留配置，点击“保存配置”，密钥文件路径一并保存。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果不需要签名，保持“启用强签名”未勾选即可。&lt;/p&gt;
&lt;h2&gt;适用场景推荐&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;原始程序集已有强签名&lt;/strong&gt;：使用同一密钥重新签名，保证引用兼容。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;需要部署到 GAC 的类库&lt;/strong&gt;：GAC 中的 DLL 必须具有强名称，混淆后需重签。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对发布文件有完整性要求&lt;/strong&gt;：利用强制签名校验检测文件是否被篡改。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;团队或客户规范要求&lt;/strong&gt;：某些企业要求所有发布程序集必须签名。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;如何验证签名结果&lt;/h2&gt;
&lt;p&gt;在开发者命令提示符中执行以下命令：&lt;/p&gt;
&lt;pre class=&quot;prism-highlight prism-language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;sn -T 输出文件.dll
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;将显示的公钥标记与原始程序集对比：使用同一密钥时，两者应一致，说明引用标识已保留。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1788181005505_38869b89.png&quot; alt=&quot;使用sn命令查看公钥标记&quot;&gt;&lt;/p&gt;
&lt;h2&gt;注意事项&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;保护好密钥文件&lt;/strong&gt;：.snk 文件包含私钥，泄露后他人可仿冒你的标识。不要提交到公开仓库或随安装包分发。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用同一密钥&lt;/strong&gt;：若要延续引用，必须用与原始程序集相同的密钥，否则公钥标记改变导致加载失败。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;强签名不是数字证书&lt;/strong&gt;：它不同于 Authenticode 签名，后者用于验证发布者身份，两者可并存。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;.NET Core 行为不同&lt;/strong&gt;：.NET Framework 中 GAC 会校验签名，而 .NET Core 及更高版本默认不校验，强名称主要用于标识。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不能替代混淆&lt;/strong&gt;：强签名不提升反编译防护强度，仍需要结合混淆和加密功能。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;与防篡改选项的区别&lt;/strong&gt;：软件中的“防篡改（仅限EXE）”是运行时保护，强签名是静态校验，可配合使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;恒盾C#混淆加密大师的强签名功能，专门解决“混淆后原签名失效”的痛点。对于已有强签名的程序集，用原密钥重签可保持引用兼容；需要 GAC 部署或签名规范时，也可为输出文件补签。&lt;/p&gt;
&lt;p&gt;记住两点：延续引用必须用同一密钥；密钥需严格保密。将强签名与混淆、加密结合，能让发布的 C# 程序集既有完整标识，又具备反编译防护能力。&lt;/p&gt;
</description><pubDate>Mon, 31 Aug 2026 20:56:42 +0800</pubDate></item><item><title>HTML打包APK User Agent设置详解</title><link>https://www.ylongsoft.com/post/html-apk-user-agent-zblog-ylongsoft.html</link><description>&lt;p&gt;每个APP在访问网站时，都会向网站发送User Agent信息，表明自己的设备和浏览器类型。网站根据此信息决定返回手机版还是电脑版内容，或提示&amp;quot;请使用指定浏览器打开&amp;quot;。&lt;/p&gt;
&lt;p&gt;HTML一键打包APK工具提供的&lt;strong&gt;User Agent设置&lt;/strong&gt;功能，允许你为打包的APP自定义此信息，使网站将APP识别为指定的浏览器或设备，从而正确展示内容。&lt;/p&gt;
&lt;p&gt;如果对工具不熟悉，可访问官网了解：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://leapever.com/intro/apk-packer&quot;&gt;HTML一键打包APK工具官网&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;User Agent设置的应用场景&lt;/h2&gt;
&lt;p&gt;大多数情况下，保持默认（留空）即可正常访问。以下场景需要自定义：&lt;/p&gt;
&lt;h3&gt;页面显示为电脑版&lt;/h3&gt;
&lt;p&gt;某些网站根据访问设备自动切换版本。若网站将APP误认为电脑浏览器，用户将看到排版混乱的电脑版。将User Agent设为手机浏览器后，网站返回手机版。&lt;/p&gt;
&lt;h3&gt;提示&amp;quot;请使用指定浏览器打开&amp;quot;&lt;/h3&gt;
&lt;p&gt;部分网站或活动页对特定环境开放，如仅允许微信内或某品牌浏览器访问，默认身份会被拦截。将User Agent改为所需身份即可访问。&lt;/p&gt;
&lt;h3&gt;统计识别APP来源&lt;/h3&gt;
&lt;p&gt;若同时运营网站，可为APP设置专属User Agent，便于在后台区分来自APP的访问。&lt;/p&gt;
&lt;h2&gt;设置位置&lt;/h2&gt;
&lt;p&gt;打开工具，在&lt;strong&gt;快速打包&lt;/strong&gt;页面中找到&lt;strong&gt;User Agent设置&lt;/strong&gt;输入框，位于时间限制和App包名之间。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1787836667884_0ef8589a.png&quot; alt=&quot;User Agent设置位置&quot;&gt;&lt;/p&gt;
&lt;h2&gt;设置步骤&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;打开工具，进入&lt;strong&gt;快速打包&lt;/strong&gt;页面。&lt;/li&gt;
&lt;li&gt;输入网址或选择本地HTML文件。&lt;/li&gt;
&lt;li&gt;在&lt;strong&gt;User Agent设置&lt;/strong&gt;中输入所需的User Agent字符串（网上可查各类浏览器的UA）。&lt;/li&gt;
&lt;li&gt;填写应用名称、包名等常规配置。&lt;/li&gt;
&lt;li&gt;点击&lt;strong&gt;打包APK&lt;/strong&gt;，等待生成。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;安装后，APP将以自定义User Agent访问网站，对内部所有网页统一生效。&lt;/p&gt;
&lt;h2&gt;留空与填写的区别&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;留空（推荐）&lt;/strong&gt;：使用系统默认User Agent，兼容性最佳。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;填写&lt;/strong&gt;：以指定身份访问，适用于特殊限制场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;使用建议&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;不确定时优先留空。&lt;/li&gt;
&lt;li&gt;仅当遇到页面异常或访问限制时再修改。&lt;/li&gt;
&lt;li&gt;修改后务必在手机上充分测试。&lt;/li&gt;
&lt;li&gt;若页面异常，清空输入框重新打包即可恢复。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;常见问题&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;会影响其他功能吗？&lt;/strong&gt;
不会，只改变访问时的身份标识。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;修改后需要重新打包吗？&lt;/strong&gt;
需要，User Agent在打包时写入，修改后需重新安装APK。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;能否为不同页面设置不同User Agent？&lt;/strong&gt;
不可以，该设置为全局统一。若需差异化，建议在网站端处理。&lt;/p&gt;
&lt;h2&gt;相关阅读&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://leapever.com/intro/apk-packer&quot;&gt;HTML一键打包APK工具官网&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://api.leapever.com/apkpacker/download&quot;&gt;立即下载HTML一键打包APK工具&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://leapever.com/tutorial/html-apk-print&quot;&gt;HTML打包APK实现页面打印功能教程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://leapever.com/tutorial/html2apk-local-file-encryption-guide&quot;&gt;5分钟学会如何使用HTML打包APK的文件加密功能&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://leapever.com/tutorial/html2apk-package-name-guide&quot;&gt;HTML一键打包APK工具使用指南 - 为什么APP安装时会覆盖&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description><pubDate>Thu, 27 Aug 2026 21:17:46 +0800</pubDate></item><item><title>HTML打包APK：页面打印功能实现方法</title><link>https://www.ylongsoft.com/post/html-apk-print-zblog-ylongsoft.html</link><description>&lt;p&gt;在网页中，一行 &lt;code&gt;window.print()&lt;/code&gt; 就能调起浏览器的打印功能。在HTML一键打包APK工具生成的APP中，这行代码同样有效：工具会拦截 &lt;code&gt;window.print()&lt;/code&gt; 调用，并转交给安卓系统打印服务。用户可以直接选择打印机打印，也可以&amp;quot;另存为PDF&amp;quot;把页面保存成PDF文件。&lt;/p&gt;
&lt;p&gt;如果你不了解HTML打包APK工具, 想要进一步了解, 可以查看官网:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://html2apk.leapever.com/&quot;&gt;HTML一键打包APK工具官网&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;创建打印页面&lt;/h2&gt;
&lt;p&gt;在HTML项目入口目录中创建 &lt;code&gt;index.html&lt;/code&gt;，写入以下代码。页面展示一张简单的单据，点击&amp;quot;打印&amp;quot;按钮后调用 &lt;code&gt;window.print()&lt;/code&gt; 触发打印。通过 &lt;code&gt;@media print&lt;/code&gt; 样式，打印时会自动隐藏按钮等屏幕元素，只保留单据内容。&lt;/p&gt;
&lt;pre class=&quot;prism-highlight prism-language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!doctype html&amp;gt;
&amp;lt;html lang=&amp;quot;zh-CN&amp;quot;&amp;gt;
    &amp;lt;head&amp;gt;
        &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot; /&amp;gt;
        &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1, viewport-fit=cover&amp;quot; /&amp;gt;
        &amp;lt;title&amp;gt;单据打印&amp;lt;/title&amp;gt;
        &amp;lt;style&amp;gt;
            * {
                box-sizing: border-box;
            }

            body {
                min-height: 100vh;
                margin: 0;
                padding: 20px;
                display: grid;
                place-items: center;
                font-family: 'Microsoft YaHei', sans-serif;
                background: #f4f7f5;
                color: #17221c;
            }

            main {
                width: min(100%, 440px);
            }

            .sheet {
                padding: 24px;
                border: 1px solid #cad4ce;
                border-radius: 8px;
                background: #fff;
            }

            h1 {
                margin: 0 0 4px;
                font-size: 24px;
                text-align: center;
            }

            .sheet-meta {
                margin: 0 0 16px;
                font-size: 13px;
                color: #526159;
                text-align: center;
            }

            table {
                width: 100%;
                border-collapse: collapse;
                font-size: 14px;
            }

            th,
            td {
                padding: 8px 6px;
                border-bottom: 1px solid #e2e8e4;
                text-align: left;
            }

            th {
                background: #eef2f0;
            }

            .total {
                margin-top: 12px;
                text-align: right;
                font-size: 16px;
                font-weight: 700;
            }

            button {
                width: 100%;
                min-height: 48px;
                margin-top: 14px;
                border: 0;
                border-radius: 6px;
                background: #197447;
                color: white;
                font: inherit;
                font-weight: 700;
            }

            /* 打印相关样式 */
            @media print {
                body {
                    padding: 0;
                    background: #fff;
                }

                /* 打印时隐藏按钮，只保留单据 */
                .no-print {
                    display: none;
                }

                .sheet {
                    width: 100%;
                    border: 0;
                    border-radius: 0;
                }
            }
        &amp;lt;/style&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;main&amp;gt;
            &amp;lt;div class=&amp;quot;sheet&amp;quot;&amp;gt;
                &amp;lt;h1&amp;gt;购物清单&amp;lt;/h1&amp;gt;
                &amp;lt;p class=&amp;quot;sheet-meta&amp;quot;&amp;gt;单号：20260824001　日期：2026-08-24&amp;lt;/p&amp;gt;
                &amp;lt;table&amp;gt;
                    &amp;lt;thead&amp;gt;
                        &amp;lt;tr&amp;gt;
                            &amp;lt;th&amp;gt;品名&amp;lt;/th&amp;gt;
                            &amp;lt;th&amp;gt;数量&amp;lt;/th&amp;gt;
                            &amp;lt;th&amp;gt;金额&amp;lt;/th&amp;gt;
                        &amp;lt;/tr&amp;gt;
                    &amp;lt;/thead&amp;gt;
                    &amp;lt;tbody&amp;gt;
                        &amp;lt;tr&amp;gt;
                            &amp;lt;td&amp;gt;无线鼠标&amp;lt;/td&amp;gt;
                            &amp;lt;td&amp;gt;1&amp;lt;/td&amp;gt;
                            &amp;lt;td&amp;gt;79.00&amp;lt;/td&amp;gt;
                        &amp;lt;/tr&amp;gt;
                        &amp;lt;tr&amp;gt;
                            &amp;lt;td&amp;gt;机械键盘&amp;lt;/td&amp;gt;
                            &amp;lt;td&amp;gt;1&amp;lt;/td&amp;gt;
                            &amp;lt;td&amp;gt;299.00&amp;lt;/td&amp;gt;
                        &amp;lt;/tr&amp;gt;
                        &amp;lt;tr&amp;gt;
                            &amp;lt;td&amp;gt;USB数据线&amp;lt;/td&amp;gt;
                            &amp;lt;td&amp;gt;2&amp;lt;/td&amp;gt;
                            &amp;lt;td&amp;gt;30.00&amp;lt;/td&amp;gt;
                        &amp;lt;/tr&amp;gt;
                    &amp;lt;/tbody&amp;gt;
                &amp;lt;/table&amp;gt;
                &amp;lt;p class=&amp;quot;total&amp;quot;&amp;gt;合计：408.00 元&amp;lt;/p&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;button class=&amp;quot;no-print&amp;quot; type=&amp;quot;button&amp;quot; onclick=&amp;quot;window.print()&amp;quot;&amp;gt;打印&amp;lt;/button&amp;gt;
        &amp;lt;/main&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;代码说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;点击&amp;quot;打印&amp;quot;按钮执行 &lt;code&gt;window.print()&lt;/code&gt;，这是整个打印功能的核心，不需要引入任何第三方库。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@media print&lt;/code&gt; 中定义了打印时的样式，&lt;code&gt;display: none&lt;/code&gt; 的 &lt;code&gt;.no-print&lt;/code&gt; 元素（按钮等）不会出现在打印内容中。&lt;/li&gt;
&lt;li&gt;单据表格、金额等内容在屏幕和打印中都会完整保留。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;打包APK&lt;/h2&gt;
&lt;p&gt;打开HTML一键打包APK工具，选择包含 &lt;code&gt;index.html&lt;/code&gt; 的项目目录，填写应用名称、包名等打包信息。打印功能依赖安卓系统打印服务，无需额外勾选权限，按默认配置打包即可。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1787574900146_fbe902d2.jpg&quot; alt=&quot;打包APK生成应用&quot;&gt;&lt;/p&gt;
&lt;p&gt;确认配置后开始打包，等待工具生成APK文件。&lt;/p&gt;
&lt;h2&gt;安装并测试打印&lt;/h2&gt;
&lt;p&gt;将生成的APK安装到安卓手机，打开APP点击&amp;quot;打印&amp;quot;按钮，系统会弹出打印预览界面。在这里可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;选择已连接的打印机（云打印机、局域网打印机等）直接打印；&lt;/li&gt;
&lt;li&gt;在打印机列表中选择&amp;quot;另存为PDF&amp;quot;，把页面保存成PDF文件。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;保存的PDF文件可以在手机的&amp;quot;文件&amp;quot;应用或相册中找到，方便发送给客户或存档。&lt;/p&gt;
&lt;h2&gt;常见问题&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;点击打印没有反应？&lt;/strong&gt; 请确认手机系统为Android 5.0及以上，旧系统没有内置打印服务。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;列表中找不到打印机？&lt;/strong&gt; 安卓打印服务需要打印机与手机处于同一网络，或打印机已接入云打印服务。也可以直接使用&amp;quot;另存为PDF&amp;quot;，不依赖任何打印机。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;打印内容不完整或分页异常？&lt;/strong&gt; 在 &lt;code&gt;@media print&lt;/code&gt; 中适当调整宽度、字号和间距，避免内容超出纸张范围；需要强制分页时，可以在指定元素上添加 &lt;code&gt;page-break-after: always&lt;/code&gt; 样式。&lt;/p&gt;
</description><pubDate>Mon, 24 Aug 2026 20:34:58 +0800</pubDate></item><item><title>HTML打包EXE退出密码设置指南</title><link>https://www.ylongsoft.com/post/html2exe-exit-password-guide.html</link><description>&lt;p&gt;HTML打包EXE工具提供了&lt;strong&gt;退出密码&lt;/strong&gt;功能。启用后，打包生成的 EXE 在用户点击关闭按钮时，不会直接退出，而是先弹出密码输入窗口，只有输入正确的退出密码才能真正关闭程序。&lt;/p&gt;
&lt;p&gt;对于放置在公共场所的展示机、教学机房的课件程序、无人值守的查询设备等场景，这个功能可以有效防止程序被误操作或他人随意关闭，保证内容持续稳定地展示和运行。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1787145032842_6520dd46.png&quot; alt=&quot;退出密码配置&quot;&gt;&lt;/p&gt;
&lt;h2&gt;下载最新版本&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://api.leapever.com/packerv2/download&quot;&gt;立即下载最新版本&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://leapever.com/intro/html2exe&quot;&gt;HTML打包EXE工具官网&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;适用场景&lt;/h2&gt;
&lt;p&gt;退出密码功能适合需要让程序保持长时间运行、不希望被随意关闭的使用方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;展厅展示机&lt;/strong&gt;：触摸屏一体机循环播放展示内容，防止参观者误触关闭按钮退出程序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;教学机房&lt;/strong&gt;：学生机上的课件程序保持打开状态，避免学生上课途中关闭课件。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;无人值守设备&lt;/strong&gt;：自助查询机、叫号机等设备需要程序持续运行，只有管理人员输入密码才能退出维护。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;儿童使用场景&lt;/strong&gt;：孩子使用电脑学习时，防止其随手关闭学习软件去做其他操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;会议和活动现场&lt;/strong&gt;：现场大屏播放的程序避免被工作人员误关，影响活动流程。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;简单来说，只要你的程序需要&amp;quot;一直开着&amp;quot;，退出密码就能帮上忙。&lt;/p&gt;
&lt;h2&gt;配置步骤&lt;/h2&gt;
&lt;p&gt;退出密码位于打包工具的&lt;strong&gt;静态密码&lt;/strong&gt;标签页中，配置步骤如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开 HTML打包EXE 工具，切换到&lt;strong&gt;静态密码&lt;/strong&gt;标签页。&lt;/li&gt;
&lt;li&gt;勾选&lt;strong&gt;启用退出密码功能&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;勾选后，下方的&lt;strong&gt;退出密码&lt;/strong&gt;输入框会变为可编辑状态，输入 1-16 位字母或数字作为退出密码。&lt;/li&gt;
&lt;li&gt;正常执行打包操作，生成 EXE。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;需要注意的是，&lt;strong&gt;未勾选&amp;quot;启用退出密码功能&amp;quot;时，退出密码输入框为灰色不可编辑状态&lt;/strong&gt;。只有先勾选启用，才能填写和修改密码，避免误填了密码却没有实际启用功能的情况。&lt;/p&gt;
&lt;h2&gt;用户看到的效果&lt;/h2&gt;
&lt;p&gt;打包生成的 EXE 运行后，用户点击窗口关闭按钮时，会弹出&amp;quot;需要退出密码&amp;quot;的提示窗口，要求输入退出密码。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1787145033254_d47365a6.png&quot; alt=&quot;退出密码弹窗效果&quot;&gt;&lt;/p&gt;
&lt;p&gt;用户可以选择：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;输入正确的退出密码并确认，程序正常退出。&lt;/li&gt;
&lt;li&gt;输入错误密码，程序不会退出，需要重新输入。&lt;/li&gt;
&lt;li&gt;点击取消，放弃退出操作，程序继续运行。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;也就是说，不知道密码的用户无法通过常规方式关闭程序，只有掌握密码的管理人员才能退出。&lt;/p&gt;
&lt;h2&gt;和静态密码的区别&lt;/h2&gt;
&lt;p&gt;静态密码和退出密码位于同一个标签页，但作用阶段不同：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;对比项&lt;/th&gt;
&lt;th&gt;静态密码&lt;/th&gt;
&lt;th&gt;退出密码&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;作用时机&lt;/td&gt;
&lt;td&gt;打开程序时&lt;/td&gt;
&lt;td&gt;关闭程序时&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;作用&lt;/td&gt;
&lt;td&gt;输入正确密码才能进入软件&lt;/td&gt;
&lt;td&gt;输入正确密码才能退出软件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;适合场景&lt;/td&gt;
&lt;td&gt;限制谁可以使用软件&lt;/td&gt;
&lt;td&gt;防止软件被随意关闭&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;自定义信息&lt;/td&gt;
&lt;td&gt;支持配置激活弹窗显示的信息&lt;/td&gt;
&lt;td&gt;使用固定的提示信息&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;两者可以单独使用，也可以同时启用。例如一个付费展示项目，可以设置静态密码限制只有付费用户才能打开，再设置退出密码防止展示过程中被关闭，实现&amp;quot;进得来就出不去&amp;quot;的双重保护。&lt;/p&gt;
&lt;h2&gt;使用建议&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;妥善保管密码&lt;/strong&gt;：退出密码设置后只有自己知道，请务必记录保存。如果忘记密码，程序将无法正常退出。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使用容易输入的密码&lt;/strong&gt;：密码支持 1-16 位字母和数字，建议使用便于记忆和快速输入的组合，方便现场维护人员操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配合全屏使用效果更好&lt;/strong&gt;：对于展示机场景，建议同时勾选&lt;strong&gt;全屏&lt;/strong&gt;选项，隐藏窗口的放大、缩小、关闭按钮，配合退出密码形成更完整的防关闭方案。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注意内核支持&lt;/strong&gt;：退出密码功能仅 Chrome 内核支持，打包时请确认内核选择为 Chrome 内核。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;定期更换密码&lt;/strong&gt;：如果程序长期放置在公共场所，建议定期更换退出密码并重新打包，避免密码泄露。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;HTML打包EXE工具的退出密码功能，配置简单但非常实用：勾选启用、填写密码、重新打包，三步即可让生成的 EXE 具备防关闭能力。&lt;/p&gt;
&lt;p&gt;对于展厅展示、教学机房、无人值守设备等需要程序持续运行的场景，退出密码可以有效避免误操作和恶意关闭。如果再配合静态密码、全屏等选项一起使用，就能让打包出来的程序既安全又稳定。&lt;/p&gt;
&lt;h2&gt;相关阅读&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;./html2exe-encryption-comparison.md&quot;&gt;HTML打包EXE三种加密方式对比&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./html2exe-encrypt-tutorial.md&quot;&gt;离线一机一码使用详细教程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;./offline-vs-network-verification.md&quot;&gt;离线一机一码验证和网络验证的区别&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description><pubDate>Wed, 19 Aug 2026 21:10:33 +0800</pubDate></item><item><title>用HTML打包APK制作视频播放器</title><link>https://www.ylongsoft.com/post/html-apk-video-fullscreen-player.html</link><description>&lt;p&gt;HTML页面可以通过 &lt;code&gt;video&lt;/code&gt; 标签播放网络和本地视频，结合浏览器全屏接口实现最大化播放，并在全屏时锁定横屏获得更好的观看体验。完成页面代码后，再通过HTML一键打包APK工具配置网络权限，即可生成支持视频播放和全屏播放的安卓APP。&lt;/p&gt;&lt;p&gt;工具官网：&lt;a href=&quot;https://html2apk.leapever.com/&quot;&gt;HTML一键打包APK工具官网&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;创建视频播放页面&lt;/h2&gt;&lt;p&gt;在项目入口目录创建 &lt;code&gt;index.html&lt;/code&gt;，包含视频播放区、最大化按钮和地址输入。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;视频播放：使用 &lt;code&gt;video&lt;/code&gt; 标签加载视频，添加 &lt;code&gt;playsinline&lt;/code&gt; 属性保证内联播放。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;最大化按钮：调用全屏接口，兼容WebView。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;横屏锁定：全屏时自动横屏，退出竖屏。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;地址加载：输入视频直链，切换测试视频。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;视频标签需要添加 &lt;code&gt;playsinline&lt;/code&gt;、&lt;code&gt;webkit-playsinline&lt;/code&gt; 和 &lt;code&gt;x5-playsinline&lt;/code&gt; 属性，避免跳转系统播放器：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-html&quot;&gt;&amp;lt;video&amp;nbsp;playsinline&amp;nbsp;webkit-playsinline&amp;nbsp;x5-playsinline&amp;nbsp;src=&amp;quot;video.mp4&amp;quot;&amp;gt;&amp;lt;/video&amp;gt;&lt;/pre&gt;&lt;p&gt;最大化按钮通过全屏接口处理标准接口和 &lt;code&gt;webkit&lt;/code&gt; 前缀接口：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-javascript&quot;&gt;if&amp;nbsp;(shell.requestFullscreen)&amp;nbsp;shell.requestFullscreen();
else&amp;nbsp;if&amp;nbsp;(shell.webkitRequestFullscreen)&amp;nbsp;shell.webkitRequestFullscreen();&lt;/pre&gt;&lt;h2&gt;打包成APK&lt;/h2&gt;&lt;p&gt;保存代码到video-test.html，用工具载入并点击打包：&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1786361556729_009c39d2.png&quot; alt=&quot;把html打包成apk&quot;/&gt;&lt;/p&gt;&lt;h2&gt;测试功能&lt;/h2&gt;&lt;p&gt;安装APK后测试：&lt;/p&gt;&lt;ol class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;默认视频加载，播放暂停正常。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;点最大化按钮进入全屏。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;全屏时横屏锁定，退出恢复竖屏。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;输入其他mp4链接，切换加载。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;拖动进度条，从指定位置播放。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;推荐H.264+AAC编码的mp4，避免HEVC等兼容问题。&lt;/p&gt;&lt;p&gt;如果全屏失效，检查系统横屏限制；视频加载失败，确认网络权限和地址可用。自动播放需要用户交互。&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1786361557143_3e5d1044.png&quot; alt=&quot;视频播放和最大化页面&quot;/&gt;&lt;/p&gt;&lt;p&gt;完整示例：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-html&quot;&gt;&amp;lt;!DOCTYPE&amp;nbsp;html&amp;gt;
&amp;lt;html&amp;nbsp;lang=&amp;quot;zh-CN&amp;quot;&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;meta&amp;nbsp;charset=&amp;quot;UTF-8&amp;quot;&amp;gt;
&amp;lt;meta&amp;nbsp;name=&amp;quot;viewport&amp;quot;&amp;nbsp;content=&amp;quot;width=device-width,&amp;nbsp;initial-scale=1.0,&amp;nbsp;maximum-scale=1.0,&amp;nbsp;user-scalable=no&amp;quot;&amp;gt;
&amp;lt;title&amp;gt;视频播放测试&amp;lt;/title&amp;gt;
&amp;lt;style&amp;gt;
&amp;nbsp;&amp;nbsp;*&amp;nbsp;{&amp;nbsp;margin:&amp;nbsp;0;&amp;nbsp;padding:&amp;nbsp;0;&amp;nbsp;box-sizing:&amp;nbsp;border-box;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;html,&amp;nbsp;body&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;width:&amp;nbsp;100%;&amp;nbsp;height:&amp;nbsp;100%;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;#000;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-family:&amp;nbsp;-apple-system,&amp;nbsp;&amp;quot;PingFang&amp;nbsp;SC&amp;quot;,&amp;nbsp;&amp;quot;Microsoft&amp;nbsp;YaHei&amp;quot;,&amp;nbsp;sans-serif;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;overflow:&amp;nbsp;hidden;
&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;#player-wrap&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;position:&amp;nbsp;relative;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;width:&amp;nbsp;100%;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;height:&amp;nbsp;100%;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;display:&amp;nbsp;flex;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;flex-direction:&amp;nbsp;column;
&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;/*&amp;nbsp;视频区域&amp;nbsp;*/
&amp;nbsp;&amp;nbsp;#video-box&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;position:&amp;nbsp;relative;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;flex:&amp;nbsp;1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;#000;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;display:&amp;nbsp;flex;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;align-items:&amp;nbsp;center;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;justify-content:&amp;nbsp;center;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;overflow:&amp;nbsp;hidden;
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;video&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;width:&amp;nbsp;100%;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;height:&amp;nbsp;100%;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;object-fit:&amp;nbsp;contain;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;#000;
&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;/*&amp;nbsp;最大化按钮（悬浮在视频右上角）&amp;nbsp;*/
&amp;nbsp;&amp;nbsp;#btn-fullscreen&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;position:&amp;nbsp;absolute;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;top:&amp;nbsp;12px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;right:&amp;nbsp;12px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;z-index:&amp;nbsp;20;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;width:&amp;nbsp;44px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;height:&amp;nbsp;44px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border:&amp;nbsp;none;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border-radius:&amp;nbsp;8px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;rgba(0,&amp;nbsp;0,&amp;nbsp;0,&amp;nbsp;0.55);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color:&amp;nbsp;#fff;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;display:&amp;nbsp;flex;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;align-items:&amp;nbsp;center;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;justify-content:&amp;nbsp;center;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor:&amp;nbsp;pointer;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-webkit-tap-highlight-color:&amp;nbsp;transparent;
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;#btn-fullscreen:active&amp;nbsp;{&amp;nbsp;background:&amp;nbsp;rgba(255,&amp;nbsp;255,&amp;nbsp;255,&amp;nbsp;0.25);&amp;nbsp;}
&amp;nbsp;&amp;nbsp;#btn-fullscreen&amp;nbsp;svg&amp;nbsp;{&amp;nbsp;width:&amp;nbsp;24px;&amp;nbsp;height:&amp;nbsp;24px;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;/*&amp;nbsp;底部控制栏&amp;nbsp;*/
&amp;nbsp;&amp;nbsp;#controls&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;position:&amp;nbsp;relative;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;z-index:&amp;nbsp;10;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;#111;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padding:&amp;nbsp;10px&amp;nbsp;12px&amp;nbsp;calc(10px&amp;nbsp;+&amp;nbsp;env(safe-area-inset-bottom));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;display:&amp;nbsp;flex;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;flex-direction:&amp;nbsp;column;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;gap:&amp;nbsp;10px;
&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;#btn-play&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;width:&amp;nbsp;100%;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padding:&amp;nbsp;14px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-size:&amp;nbsp;17px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color:&amp;nbsp;#fff;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;#1f80ff;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border:&amp;nbsp;none;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border-radius:&amp;nbsp;10px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-webkit-tap-highlight-color:&amp;nbsp;transparent;
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;#btn-play:active&amp;nbsp;{&amp;nbsp;opacity:&amp;nbsp;0.8;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;.url-row&amp;nbsp;{&amp;nbsp;display:&amp;nbsp;flex;&amp;nbsp;gap:&amp;nbsp;8px;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;#url-input&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;flex:&amp;nbsp;1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min-width:&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padding:&amp;nbsp;12px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-size:&amp;nbsp;14px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color:&amp;nbsp;#fff;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;#222;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border:&amp;nbsp;1px&amp;nbsp;solid&amp;nbsp;#333;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border-radius:&amp;nbsp;8px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;outline:&amp;nbsp;none;
&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;#btn-load&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padding:&amp;nbsp;0&amp;nbsp;16px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-size:&amp;nbsp;14px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color:&amp;nbsp;#fff;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;#333;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border:&amp;nbsp;none;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border-radius:&amp;nbsp;8px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;white-space:&amp;nbsp;nowrap;
&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;#status&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-size:&amp;nbsp;12px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color:&amp;nbsp;#888;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;word-break:&amp;nbsp;break-all;
&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;/*&amp;nbsp;全屏时隐藏控制栏&amp;nbsp;*/
&amp;nbsp;&amp;nbsp;:fullscreen&amp;nbsp;#controls&amp;nbsp;{&amp;nbsp;display:&amp;nbsp;none;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;:-webkit-full-screen&amp;nbsp;#controls&amp;nbsp;{&amp;nbsp;display:&amp;nbsp;none;&amp;nbsp;}
&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

&amp;lt;div&amp;nbsp;id=&amp;quot;player-wrap&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;div&amp;nbsp;id=&amp;quot;video-box&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;video&amp;nbsp;id=&amp;quot;video&amp;quot;&amp;nbsp;playsinline&amp;nbsp;webkit-playsinline&amp;nbsp;x5-playsinline&amp;nbsp;preload=&amp;quot;metadata&amp;quot;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;src=&amp;quot;./BigBuckBunny.mp4&amp;quot;&amp;gt;&amp;lt;/video&amp;gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;!--&amp;nbsp;最大化按钮&amp;nbsp;--&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;button&amp;nbsp;id=&amp;quot;btn-fullscreen&amp;quot;&amp;nbsp;aria-label=&amp;quot;最大化&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;svg&amp;nbsp;id=&amp;quot;icon-max&amp;quot;&amp;nbsp;viewBox=&amp;quot;0&amp;nbsp;0&amp;nbsp;24&amp;nbsp;24&amp;quot;&amp;nbsp;fill=&amp;quot;none&amp;quot;&amp;nbsp;stroke=&amp;quot;currentColor&amp;quot;&amp;nbsp;stroke-width=&amp;quot;2&amp;quot;&amp;nbsp;stroke-linecap=&amp;quot;round&amp;quot;&amp;nbsp;stroke-linejoin=&amp;quot;round&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;path&amp;nbsp;d=&amp;quot;M8&amp;nbsp;3H5a2&amp;nbsp;2&amp;nbsp;0&amp;nbsp;0&amp;nbsp;0-2&amp;nbsp;2v3&amp;quot;/&amp;gt;&amp;lt;path&amp;nbsp;d=&amp;quot;M16&amp;nbsp;3h3a2&amp;nbsp;2&amp;nbsp;0&amp;nbsp;0&amp;nbsp;1&amp;nbsp;2&amp;nbsp;2v3&amp;quot;/&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;path&amp;nbsp;d=&amp;quot;M8&amp;nbsp;21H5a2&amp;nbsp;2&amp;nbsp;0&amp;nbsp;0&amp;nbsp;1-2-2v-3&amp;quot;/&amp;gt;&amp;lt;path&amp;nbsp;d=&amp;quot;M16&amp;nbsp;21h3a2&amp;nbsp;2&amp;nbsp;0&amp;nbsp;0&amp;nbsp;0&amp;nbsp;2-2v-3&amp;quot;/&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/svg&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;svg&amp;nbsp;id=&amp;quot;icon-min&amp;quot;&amp;nbsp;viewBox=&amp;quot;0&amp;nbsp;0&amp;nbsp;24&amp;nbsp;24&amp;quot;&amp;nbsp;fill=&amp;quot;none&amp;quot;&amp;nbsp;stroke=&amp;quot;currentColor&amp;quot;&amp;nbsp;stroke-width=&amp;quot;2&amp;quot;&amp;nbsp;stroke-linecap=&amp;quot;round&amp;quot;&amp;nbsp;stroke-linejoin=&amp;quot;round&amp;quot;&amp;nbsp;style=&amp;quot;display:none&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;path&amp;nbsp;d=&amp;quot;M8&amp;nbsp;3v3a2&amp;nbsp;2&amp;nbsp;0&amp;nbsp;0&amp;nbsp;1-2&amp;nbsp;2H3&amp;quot;/&amp;gt;&amp;lt;path&amp;nbsp;d=&amp;quot;M21&amp;nbsp;8h-3a2&amp;nbsp;2&amp;nbsp;0&amp;nbsp;0&amp;nbsp;1-2-2V3&amp;quot;/&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;path&amp;nbsp;d=&amp;quot;M3&amp;nbsp;16h3a2&amp;nbsp;2&amp;nbsp;0&amp;nbsp;0&amp;nbsp;1&amp;nbsp;2&amp;nbsp;2v3&amp;quot;/&amp;gt;&amp;lt;path&amp;nbsp;d=&amp;quot;M16&amp;nbsp;21v-3a2&amp;nbsp;2&amp;nbsp;0&amp;nbsp;0&amp;nbsp;1&amp;nbsp;2-2h3&amp;quot;/&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/svg&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/button&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;/div&amp;gt;

&amp;nbsp;&amp;nbsp;&amp;lt;div&amp;nbsp;id=&amp;quot;controls&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;button&amp;nbsp;id=&amp;quot;btn-play&amp;quot;&amp;gt;播放&amp;nbsp;/&amp;nbsp;暂停&amp;lt;/button&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;div&amp;nbsp;class=&amp;quot;url-row&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;input&amp;nbsp;id=&amp;quot;url-input&amp;quot;&amp;nbsp;type=&amp;quot;url&amp;quot;&amp;nbsp;placeholder=&amp;quot;输入视频地址&amp;nbsp;(mp4/m3u8直链)&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;button&amp;nbsp;id=&amp;quot;btn-load&amp;quot;&amp;gt;加载&amp;lt;/button&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;div&amp;nbsp;id=&amp;quot;status&amp;quot;&amp;gt;就绪&amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;script&amp;gt;
(function&amp;nbsp;()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;var&amp;nbsp;wrap&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;player-wrap&amp;#39;);
&amp;nbsp;&amp;nbsp;var&amp;nbsp;video&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;video&amp;#39;);
&amp;nbsp;&amp;nbsp;var&amp;nbsp;btnFs&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;btn-fullscreen&amp;#39;);
&amp;nbsp;&amp;nbsp;var&amp;nbsp;btnPlay&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;btn-play&amp;#39;);
&amp;nbsp;&amp;nbsp;var&amp;nbsp;btnLoad&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;btn-load&amp;#39;);
&amp;nbsp;&amp;nbsp;var&amp;nbsp;urlInput&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;url-input&amp;#39;);
&amp;nbsp;&amp;nbsp;var&amp;nbsp;status&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;status&amp;#39;);
&amp;nbsp;&amp;nbsp;var&amp;nbsp;iconMax&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;icon-max&amp;#39;);
&amp;nbsp;&amp;nbsp;var&amp;nbsp;iconMin&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;icon-min&amp;#39;);

&amp;nbsp;&amp;nbsp;function&amp;nbsp;setStatus(msg)&amp;nbsp;{&amp;nbsp;status.textContent&amp;nbsp;=&amp;nbsp;msg;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;function&amp;nbsp;isFullscreen()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;!!(document.fullscreenElement&amp;nbsp;||&amp;nbsp;document.webkitFullscreenElement&amp;nbsp;||
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;document.webkitCurrentFullScreenElement);
&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;function&amp;nbsp;updateIcon()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var&amp;nbsp;fs&amp;nbsp;=&amp;nbsp;isFullscreen();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iconMax.style.display&amp;nbsp;=&amp;nbsp;fs&amp;nbsp;?&amp;nbsp;&amp;#39;none&amp;#39;&amp;nbsp;:&amp;nbsp;&amp;#39;&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;iconMin.style.display&amp;nbsp;=&amp;nbsp;fs&amp;nbsp;?&amp;nbsp;&amp;#39;&amp;#39;&amp;nbsp;:&amp;nbsp;&amp;#39;none&amp;#39;;
&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;//&amp;nbsp;最大化&amp;nbsp;/&amp;nbsp;退出全屏（兼容&amp;nbsp;iOS&amp;nbsp;Safari&amp;nbsp;的&amp;nbsp;video&amp;nbsp;原生全屏）
&amp;nbsp;&amp;nbsp;btnFs.addEventListener(&amp;#39;click&amp;#39;,&amp;nbsp;function&amp;nbsp;()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(isFullscreen())&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(document.exitFullscreen)&amp;nbsp;document.exitFullscreen();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else&amp;nbsp;if&amp;nbsp;(document.webkitExitFullscreen)&amp;nbsp;document.webkitExitFullscreen();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else&amp;nbsp;if&amp;nbsp;(video.webkitExitFullscreen)&amp;nbsp;video.webkitExitFullscreen();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(wrap.requestFullscreen)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;wrap.requestFullscreen();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;else&amp;nbsp;if&amp;nbsp;(wrap.webkitRequestFullscreen)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;wrap.webkitRequestFullscreen();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;else&amp;nbsp;if&amp;nbsp;(video.webkitEnterFullscreen)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;iOS&amp;nbsp;Safari:&amp;nbsp;只对&amp;nbsp;video&amp;nbsp;元素有效
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;video.webkitEnterFullscreen();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;else&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;setStatus(&amp;#39;当前环境不支持全屏&amp;nbsp;API&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;});

&amp;nbsp;&amp;nbsp;[&amp;#39;fullscreenchange&amp;#39;,&amp;nbsp;&amp;#39;webkitfullscreenchange&amp;#39;].forEach(function&amp;nbsp;(ev)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;document.addEventListener(ev,&amp;nbsp;updateIcon);
&amp;nbsp;&amp;nbsp;});
&amp;nbsp;&amp;nbsp;video.addEventListener(&amp;#39;webkitendfullscreen&amp;#39;,&amp;nbsp;updateIcon);

&amp;nbsp;&amp;nbsp;//&amp;nbsp;播放&amp;nbsp;/&amp;nbsp;暂停
&amp;nbsp;&amp;nbsp;btnPlay.addEventListener(&amp;#39;click&amp;#39;,&amp;nbsp;function&amp;nbsp;()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(video.paused)&amp;nbsp;video.play().catch(function&amp;nbsp;(e)&amp;nbsp;{&amp;nbsp;setStatus(&amp;#39;播放失败:&amp;nbsp;&amp;#39;&amp;nbsp;+&amp;nbsp;e.message);&amp;nbsp;});
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else&amp;nbsp;video.pause();
&amp;nbsp;&amp;nbsp;});

&amp;nbsp;&amp;nbsp;//&amp;nbsp;加载自定义地址
&amp;nbsp;&amp;nbsp;btnLoad.addEventListener(&amp;#39;click&amp;#39;,&amp;nbsp;function&amp;nbsp;()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var&amp;nbsp;url&amp;nbsp;=&amp;nbsp;urlInput.value.trim();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(!url)&amp;nbsp;{&amp;nbsp;setStatus(&amp;#39;请输入视频地址&amp;#39;);&amp;nbsp;return;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;video.src&amp;nbsp;=&amp;nbsp;url;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;video.load();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;video.play().catch(function&amp;nbsp;()&amp;nbsp;{});
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;setStatus(&amp;#39;已加载:&amp;nbsp;&amp;#39;&amp;nbsp;+&amp;nbsp;url);
&amp;nbsp;&amp;nbsp;});

&amp;nbsp;&amp;nbsp;//&amp;nbsp;状态反馈
&amp;nbsp;&amp;nbsp;video.addEventListener(&amp;#39;playing&amp;#39;,&amp;nbsp;function&amp;nbsp;()&amp;nbsp;{&amp;nbsp;setStatus(&amp;#39;播放中&amp;nbsp;&amp;#39;&amp;nbsp;+&amp;nbsp;video.videoWidth&amp;nbsp;+&amp;nbsp;&amp;#39;x&amp;#39;&amp;nbsp;+&amp;nbsp;video.videoHeight);&amp;nbsp;});
&amp;nbsp;&amp;nbsp;video.addEventListener(&amp;#39;pause&amp;#39;,&amp;nbsp;function&amp;nbsp;()&amp;nbsp;{&amp;nbsp;setStatus(&amp;#39;已暂停&amp;#39;);&amp;nbsp;});
&amp;nbsp;&amp;nbsp;video.addEventListener(&amp;#39;error&amp;#39;,&amp;nbsp;function&amp;nbsp;()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var&amp;nbsp;err&amp;nbsp;=&amp;nbsp;video.error;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;setStatus(&amp;#39;加载出错:&amp;nbsp;&amp;#39;&amp;nbsp;+&amp;nbsp;(err&amp;nbsp;?&amp;nbsp;&amp;#39;code&amp;nbsp;&amp;#39;&amp;nbsp;+&amp;nbsp;err.code&amp;nbsp;:&amp;nbsp;&amp;#39;未知错误&amp;#39;));
&amp;nbsp;&amp;nbsp;});
&amp;nbsp;&amp;nbsp;video.addEventListener(&amp;#39;ended&amp;#39;,&amp;nbsp;function&amp;nbsp;()&amp;nbsp;{&amp;nbsp;setStatus(&amp;#39;播放结束&amp;#39;);&amp;nbsp;});
})();
&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;</description><pubDate>Mon, 10 Aug 2026 19:32:34 +0800</pubDate></item><item><title>HTML打包APK实现拍照、录像、录音和文件选择</title><link>https://www.ylongsoft.com/post/html-apk-camera-video-audio-file-picker.html</link><description>&lt;p&gt;HTML页面可以通过文件选择控件和浏览器媒体接口调用安卓设备的相机、摄像头、麦克风及文件选择器。完成页面代码后，再通过HTML一键打包APK工具配置相机和麦克风权限，即可生成支持拍照、录像、录音和文件选择的安卓APP。&lt;/p&gt;&lt;p&gt;如果你不了解HTML打包APK工具，想要进一步了解，可以查看官网：&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://html2apk.leapever.com/&quot;&gt;HTML一键打包APK工具官网&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;创建文件采集页面&lt;/h2&gt;&lt;p&gt;在HTML项目入口目录中创建 &lt;code&gt;index.html&lt;/code&gt;，加入拍摄照片、录制视频、录制音频和选择文件四个入口。&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;拍摄照片：调用设备相机并优先进入后置摄像头拍照页面。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;录制视频：调用设备摄像头并进入视频录制页面。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;录制音频：申请麦克风权限，在网页内录制音频并生成可下载的音频文件。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;选择文件：打开系统文件选择界面，并支持一次选择多个文件。也可以选择相机进行拍照或者录频&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;一个完整的html示例代码如下：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-html&quot;&gt;&amp;lt;!doctype&amp;nbsp;html&amp;gt;
&amp;lt;html&amp;nbsp;lang=&amp;quot;zh-CN&amp;quot;&amp;gt;
&amp;lt;head&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;meta&amp;nbsp;charset=&amp;quot;utf-8&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;meta&amp;nbsp;name=&amp;quot;viewport&amp;quot;&amp;nbsp;content=&amp;quot;width=device-width,&amp;nbsp;initial-scale=1,&amp;nbsp;viewport-fit=cover&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;meta&amp;nbsp;name=&amp;quot;theme-color&amp;quot;&amp;nbsp;content=&amp;quot;#f4f1ea&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;title&amp;gt;移动端文件采集&amp;lt;/title&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;style&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:root&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color-scheme:&amp;nbsp;light;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;--ink:&amp;nbsp;#18201d;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;--muted:&amp;nbsp;#65706b;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;--paper:&amp;nbsp;#f4f1ea;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;--surface:&amp;nbsp;#fffdf8;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;--line:&amp;nbsp;#d8d5cd;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;--green:&amp;nbsp;#18634b;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;--green-dark:&amp;nbsp;#104b39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;--coral:&amp;nbsp;#e56f51;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;--shadow:&amp;nbsp;0&amp;nbsp;12px&amp;nbsp;32px&amp;nbsp;rgba(24,&amp;nbsp;32,&amp;nbsp;29,&amp;nbsp;0.09);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;box-sizing:&amp;nbsp;border-box;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;letter-spacing:&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;body&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min-width:&amp;nbsp;320px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min-height:&amp;nbsp;100vh;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;margin:&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color:&amp;nbsp;var(--ink);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;linear-gradient(rgba(24,&amp;nbsp;99,&amp;nbsp;75,&amp;nbsp;0.055)&amp;nbsp;1px,&amp;nbsp;transparent&amp;nbsp;1px),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;linear-gradient(90deg,&amp;nbsp;rgba(24,&amp;nbsp;99,&amp;nbsp;75,&amp;nbsp;0.055)&amp;nbsp;1px,&amp;nbsp;transparent&amp;nbsp;1px),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var(--paper);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background-size:&amp;nbsp;24px&amp;nbsp;24px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-family:&amp;nbsp;&amp;quot;Noto&amp;nbsp;Sans&amp;nbsp;SC&amp;quot;,&amp;nbsp;&amp;quot;Microsoft&amp;nbsp;YaHei&amp;nbsp;UI&amp;quot;,&amp;nbsp;sans-serif;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;button,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;input&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font:&amp;nbsp;inherit;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[hidden]&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;display:&amp;nbsp;none&amp;nbsp;!important;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.shell&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;width:&amp;nbsp;min(100%,&amp;nbsp;560px);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min-height:&amp;nbsp;100vh;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;margin:&amp;nbsp;0&amp;nbsp;auto;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padding:&amp;nbsp;max(24px,&amp;nbsp;env(safe-area-inset-top))&amp;nbsp;18px&amp;nbsp;max(32px,&amp;nbsp;env(safe-area-inset-bottom));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;header&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;position:&amp;nbsp;relative;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padding:&amp;nbsp;12px&amp;nbsp;4px&amp;nbsp;25px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;header::after&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;position:&amp;nbsp;absolute;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;right:&amp;nbsp;4px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;bottom:&amp;nbsp;18px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;width:&amp;nbsp;52px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;height:&amp;nbsp;5px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;var(--coral);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;content:&amp;nbsp;&amp;quot;&amp;quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;transform:&amp;nbsp;rotate(-3deg);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.eyebrow&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;margin:&amp;nbsp;0&amp;nbsp;0&amp;nbsp;8px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color:&amp;nbsp;var(--green);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-size:&amp;nbsp;12px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-weight:&amp;nbsp;800;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;text-transform:&amp;nbsp;uppercase;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;h1&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;margin:&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-family:&amp;nbsp;&amp;quot;STSong&amp;quot;,&amp;nbsp;&amp;quot;SimSun&amp;quot;,&amp;nbsp;serif;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-size:&amp;nbsp;clamp(32px,&amp;nbsp;10vw,&amp;nbsp;48px);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-weight:&amp;nbsp;700;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;line-height:&amp;nbsp;1.08;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.subtitle&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;max-width:&amp;nbsp;360px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;margin:&amp;nbsp;12px&amp;nbsp;0&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color:&amp;nbsp;var(--muted);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-size:&amp;nbsp;14px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;line-height:&amp;nbsp;1.7;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.actions&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;display:&amp;nbsp;grid;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;grid-template-columns:&amp;nbsp;repeat(2,&amp;nbsp;minmax(0,&amp;nbsp;1fr));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;gap:&amp;nbsp;10px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.picker&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;position:&amp;nbsp;relative;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min-width:&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min-height:&amp;nbsp;132px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;overflow:&amp;nbsp;hidden;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border:&amp;nbsp;1px&amp;nbsp;solid&amp;nbsp;var(--line);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border-radius:&amp;nbsp;8px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;var(--surface);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;box-shadow:&amp;nbsp;0&amp;nbsp;4px&amp;nbsp;12px&amp;nbsp;rgba(24,&amp;nbsp;32,&amp;nbsp;29,&amp;nbsp;0.035);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.picker:focus-within&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;outline:&amp;nbsp;3px&amp;nbsp;solid&amp;nbsp;rgba(24,&amp;nbsp;99,&amp;nbsp;75,&amp;nbsp;0.2);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;outline-offset:&amp;nbsp;2px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.picker&amp;nbsp;input&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;position:&amp;nbsp;absolute;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;width:&amp;nbsp;1px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;height:&amp;nbsp;1px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;opacity:&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pointer-events:&amp;nbsp;none;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.picker&amp;nbsp;label&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;display:&amp;nbsp;flex;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;width:&amp;nbsp;100%;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min-height:&amp;nbsp;132px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padding:&amp;nbsp;17px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor:&amp;nbsp;pointer;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;flex-direction:&amp;nbsp;column;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;justify-content:&amp;nbsp;space-between;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-webkit-tap-highlight-color:&amp;nbsp;transparent;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.picker-button&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;display:&amp;nbsp;flex;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;width:&amp;nbsp;100%;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min-height:&amp;nbsp;132px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padding:&amp;nbsp;17px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border:&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color:&amp;nbsp;inherit;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;transparent;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor:&amp;nbsp;pointer;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;flex-direction:&amp;nbsp;column;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;justify-content:&amp;nbsp;space-between;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;text-align:&amp;nbsp;left;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-webkit-tap-highlight-color:&amp;nbsp;transparent;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.picker&amp;nbsp;label:active,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.picker-button:active&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;#f2f7f3;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.icon&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;display:&amp;nbsp;grid;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;width:&amp;nbsp;42px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;height:&amp;nbsp;42px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border-radius:&amp;nbsp;50%;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color:&amp;nbsp;#fff;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;var(--green);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-size:&amp;nbsp;20px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;place-items:&amp;nbsp;center;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.picker:nth-child(2)&amp;nbsp;.icon,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.picker:nth-child(4)&amp;nbsp;.icon&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;var(--coral);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.label-title&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;display:&amp;nbsp;block;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;margin-bottom:&amp;nbsp;4px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-size:&amp;nbsp;16px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-weight:&amp;nbsp;800;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.label-meta&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;display:&amp;nbsp;block;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;overflow:&amp;nbsp;hidden;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color:&amp;nbsp;var(--muted);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-size:&amp;nbsp;11px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;text-overflow:&amp;nbsp;ellipsis;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;white-space:&amp;nbsp;nowrap;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.result&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;margin-top:&amp;nbsp;18px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;overflow:&amp;nbsp;hidden;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border:&amp;nbsp;1px&amp;nbsp;solid&amp;nbsp;var(--line);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border-radius:&amp;nbsp;8px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;var(--surface);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;box-shadow:&amp;nbsp;var(--shadow);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;animation:&amp;nbsp;rise&amp;nbsp;240ms&amp;nbsp;ease-out;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.result-header&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;display:&amp;nbsp;flex;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min-height:&amp;nbsp;52px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padding:&amp;nbsp;12px&amp;nbsp;14px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border-bottom:&amp;nbsp;1px&amp;nbsp;solid&amp;nbsp;var(--line);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;align-items:&amp;nbsp;center;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;justify-content:&amp;nbsp;space-between;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;gap:&amp;nbsp;12px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.result-header&amp;nbsp;h2&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;margin:&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-size:&amp;nbsp;15px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.clear&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;width:&amp;nbsp;34px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;height:&amp;nbsp;34px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padding:&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border:&amp;nbsp;1px&amp;nbsp;solid&amp;nbsp;var(--line);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border-radius:&amp;nbsp;50%;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color:&amp;nbsp;var(--ink);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;transparent;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor:&amp;nbsp;pointer;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-size:&amp;nbsp;20px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;line-height:&amp;nbsp;1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.file-list&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;margin:&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padding:&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;list-style:&amp;nbsp;none;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.file-list&amp;nbsp;li&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;display:&amp;nbsp;flex;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;gap:&amp;nbsp;8px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min-height:&amp;nbsp;68px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padding:&amp;nbsp;10px&amp;nbsp;14px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border-top:&amp;nbsp;1px&amp;nbsp;solid&amp;nbsp;var(--line);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;align-items:&amp;nbsp;center;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-size:&amp;nbsp;12px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.file-list&amp;nbsp;li:first-child&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border-top:&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.file-info&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min-width:&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;flex:&amp;nbsp;1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.file-name&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;display:&amp;nbsp;block;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;overflow:&amp;nbsp;hidden;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-weight:&amp;nbsp;700;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;text-overflow:&amp;nbsp;ellipsis;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;white-space:&amp;nbsp;nowrap;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.file-size&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;display:&amp;nbsp;block;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;margin-top:&amp;nbsp;4px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color:&amp;nbsp;var(--muted);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.download-button&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min-width:&amp;nbsp;76px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min-height:&amp;nbsp;40px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padding:&amp;nbsp;0&amp;nbsp;12px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border:&amp;nbsp;1px&amp;nbsp;solid&amp;nbsp;var(--green);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border-radius:&amp;nbsp;6px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color:&amp;nbsp;#fff;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;var(--green);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor:&amp;nbsp;pointer;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-weight:&amp;nbsp;800;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;flex-shrink:&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.recorder&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;margin-top:&amp;nbsp;18px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;padding:&amp;nbsp;18px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border:&amp;nbsp;1px&amp;nbsp;solid&amp;nbsp;var(--line);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border-radius:&amp;nbsp;8px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;var(--surface);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;box-shadow:&amp;nbsp;var(--shadow);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.recorder&amp;nbsp;h2&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;margin:&amp;nbsp;0&amp;nbsp;0&amp;nbsp;6px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-size:&amp;nbsp;18px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.recorder-status&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min-height:&amp;nbsp;42px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;margin:&amp;nbsp;0&amp;nbsp;0&amp;nbsp;14px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color:&amp;nbsp;var(--muted);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-size:&amp;nbsp;13px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;line-height:&amp;nbsp;1.6;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.recorder-controls&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;display:&amp;nbsp;grid;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;grid-template-columns:&amp;nbsp;1fr&amp;nbsp;1fr;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;gap:&amp;nbsp;10px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.recorder-controls&amp;nbsp;button,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.audio-fallback&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;min-height:&amp;nbsp;46px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border:&amp;nbsp;1px&amp;nbsp;solid&amp;nbsp;var(--green);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border-radius:&amp;nbsp;6px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color:&amp;nbsp;#fff;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;var(--green);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor:&amp;nbsp;pointer;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-weight:&amp;nbsp;800;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.recorder-controls&amp;nbsp;button:disabled&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cursor:&amp;nbsp;not-allowed;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;opacity:&amp;nbsp;0.45;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.audio-fallback&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;display:&amp;nbsp;grid;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;margin-top:&amp;nbsp;10px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;border-color:&amp;nbsp;var(--line);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;color:&amp;nbsp;var(--ink);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;background:&amp;nbsp;transparent;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font-size:&amp;nbsp;13px;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;place-items:&amp;nbsp;center;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@keyframes&amp;nbsp;rise&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;from&amp;nbsp;{&amp;nbsp;opacity:&amp;nbsp;0;&amp;nbsp;transform:&amp;nbsp;translateY(8px);&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;to&amp;nbsp;{&amp;nbsp;opacity:&amp;nbsp;1;&amp;nbsp;transform:&amp;nbsp;translateY(0);&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@media&amp;nbsp;(min-width:&amp;nbsp;480px)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.shell&amp;nbsp;{&amp;nbsp;padding-inline:&amp;nbsp;26px;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.picker&amp;nbsp;label&amp;nbsp;{&amp;nbsp;min-height:&amp;nbsp;144px;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;@media&amp;nbsp;(prefers-reduced-motion:&amp;nbsp;reduce)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.result&amp;nbsp;{&amp;nbsp;animation:&amp;nbsp;none;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;main&amp;nbsp;class=&amp;quot;shell&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;header&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;p&amp;nbsp;class=&amp;quot;eyebrow&amp;quot;&amp;gt;Mobile&amp;nbsp;capture&amp;nbsp;lab&amp;lt;/p&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;h1&amp;gt;从设备中采集文件&amp;lt;/h1&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;p&amp;nbsp;class=&amp;quot;subtitle&amp;quot;&amp;gt;点击一种方式，系统会打开对应的拍摄、录制或文件选择界面。&amp;lt;/p&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/header&amp;gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;section&amp;nbsp;class=&amp;quot;actions&amp;quot;&amp;nbsp;aria-label=&amp;quot;文件采集方式&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;div&amp;nbsp;class=&amp;quot;picker&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;input&amp;nbsp;id=&amp;quot;camera&amp;quot;&amp;nbsp;type=&amp;quot;file&amp;quot;&amp;nbsp;accept=&amp;quot;image/*&amp;quot;&amp;nbsp;capture=&amp;quot;environment&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;label&amp;nbsp;for=&amp;quot;camera&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;span&amp;nbsp;class=&amp;quot;icon&amp;quot;&amp;nbsp;aria-hidden=&amp;quot;true&amp;quot;&amp;gt;●&amp;lt;/span&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;span&amp;gt;&amp;lt;span&amp;nbsp;class=&amp;quot;label-title&amp;quot;&amp;gt;拍摄照片&amp;lt;/span&amp;gt;&amp;lt;span&amp;nbsp;class=&amp;quot;label-meta&amp;quot;&amp;gt;设备后置相机&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/label&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/div&amp;gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;div&amp;nbsp;class=&amp;quot;picker&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;input&amp;nbsp;id=&amp;quot;video&amp;quot;&amp;nbsp;type=&amp;quot;file&amp;quot;&amp;nbsp;accept=&amp;quot;video/*&amp;quot;&amp;nbsp;capture=&amp;quot;environment&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;label&amp;nbsp;for=&amp;quot;video&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;span&amp;nbsp;class=&amp;quot;icon&amp;quot;&amp;nbsp;aria-hidden=&amp;quot;true&amp;quot;&amp;gt;▶&amp;lt;/span&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;span&amp;gt;&amp;lt;span&amp;nbsp;class=&amp;quot;label-title&amp;quot;&amp;gt;录制视频&amp;lt;/span&amp;gt;&amp;lt;span&amp;nbsp;class=&amp;quot;label-meta&amp;quot;&amp;gt;设备摄像头&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/label&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/div&amp;gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;div&amp;nbsp;class=&amp;quot;picker&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;button&amp;nbsp;id=&amp;quot;openRecorder&amp;quot;&amp;nbsp;class=&amp;quot;picker-button&amp;quot;&amp;nbsp;type=&amp;quot;button&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;span&amp;nbsp;class=&amp;quot;icon&amp;quot;&amp;nbsp;aria-hidden=&amp;quot;true&amp;quot;&amp;gt;♪&amp;lt;/span&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;span&amp;gt;&amp;lt;span&amp;nbsp;class=&amp;quot;label-title&amp;quot;&amp;gt;录制音频&amp;lt;/span&amp;gt;&amp;lt;span&amp;nbsp;class=&amp;quot;label-meta&amp;quot;&amp;gt;设备麦克风&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/button&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/div&amp;gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;div&amp;nbsp;class=&amp;quot;picker&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;input&amp;nbsp;id=&amp;quot;files&amp;quot;&amp;nbsp;type=&amp;quot;file&amp;quot;&amp;nbsp;multiple&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;label&amp;nbsp;for=&amp;quot;files&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;span&amp;nbsp;class=&amp;quot;icon&amp;quot;&amp;nbsp;aria-hidden=&amp;quot;true&amp;quot;&amp;gt;＋&amp;lt;/span&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;span&amp;gt;&amp;lt;span&amp;nbsp;class=&amp;quot;label-title&amp;quot;&amp;gt;选择文件&amp;lt;/span&amp;gt;&amp;lt;span&amp;nbsp;class=&amp;quot;label-meta&amp;quot;&amp;gt;支持多选&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/label&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/section&amp;gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;section&amp;nbsp;id=&amp;quot;recorder&amp;quot;&amp;nbsp;class=&amp;quot;recorder&amp;quot;&amp;nbsp;aria-live=&amp;quot;polite&amp;quot;&amp;nbsp;hidden&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;h2&amp;gt;麦克风录音&amp;lt;/h2&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;p&amp;nbsp;id=&amp;quot;recorderStatus&amp;quot;&amp;nbsp;class=&amp;quot;recorder-status&amp;quot;&amp;gt;点击“开始录音”，并允许浏览器使用麦克风。&amp;lt;/p&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;div&amp;nbsp;class=&amp;quot;recorder-controls&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;button&amp;nbsp;id=&amp;quot;startRecording&amp;quot;&amp;nbsp;type=&amp;quot;button&amp;quot;&amp;gt;开始录音&amp;lt;/button&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;button&amp;nbsp;id=&amp;quot;stopRecording&amp;quot;&amp;nbsp;type=&amp;quot;button&amp;quot;&amp;nbsp;disabled&amp;gt;停止并使用&amp;lt;/button&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;input&amp;nbsp;id=&amp;quot;audioFallback&amp;quot;&amp;nbsp;type=&amp;quot;file&amp;quot;&amp;nbsp;accept=&amp;quot;audio/*&amp;quot;&amp;nbsp;hidden&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;label&amp;nbsp;class=&amp;quot;audio-fallback&amp;quot;&amp;nbsp;for=&amp;quot;audioFallback&amp;quot;&amp;gt;无法录音？选择已有音频&amp;lt;/label&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/section&amp;gt;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;section&amp;nbsp;id=&amp;quot;result&amp;quot;&amp;nbsp;class=&amp;quot;result&amp;quot;&amp;nbsp;aria-live=&amp;quot;polite&amp;quot;&amp;nbsp;hidden&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;div&amp;nbsp;class=&amp;quot;result-header&amp;quot;&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;h2&amp;nbsp;id=&amp;quot;resultTitle&amp;quot;&amp;gt;处理完成&amp;lt;/h2&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;button&amp;nbsp;id=&amp;quot;clearButton&amp;quot;&amp;nbsp;class=&amp;quot;clear&amp;quot;&amp;nbsp;type=&amp;quot;button&amp;quot;&amp;nbsp;aria-label=&amp;quot;清除选择&amp;quot;&amp;nbsp;title=&amp;quot;清除选择&amp;quot;&amp;gt;×&amp;lt;/button&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/div&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;ul&amp;nbsp;id=&amp;quot;fileList&amp;quot;&amp;nbsp;class=&amp;quot;file-list&amp;quot;&amp;gt;&amp;lt;/ul&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/section&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;lt;/main&amp;gt;

&amp;nbsp;&amp;nbsp;&amp;lt;script&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;inputs&amp;nbsp;=&amp;nbsp;document.querySelectorAll(&amp;#39;input[type=&amp;quot;file&amp;quot;]&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;result&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;result&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;resultTitle&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;resultTitle&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;fileList&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;fileList&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;clearButton&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;clearButton&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;openRecorder&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;openRecorder&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;recorderPanel&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;recorder&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;recorderStatus&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;recorderStatus&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;startRecording&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;startRecording&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;stopRecording&amp;nbsp;=&amp;nbsp;document.getElementById(&amp;#39;stopRecording&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let&amp;nbsp;activeInput&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let&amp;nbsp;microphoneStream&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let&amp;nbsp;recordingAudioContext&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let&amp;nbsp;recordingSource&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let&amp;nbsp;recordingProcessor&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let&amp;nbsp;recordingGain&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let&amp;nbsp;pcmChunks&amp;nbsp;=&amp;nbsp;[];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let&amp;nbsp;pcmSampleCount&amp;nbsp;=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let&amp;nbsp;isRecording&amp;nbsp;=&amp;nbsp;false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let&amp;nbsp;recordingTimer&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let&amp;nbsp;recordingStartedAt&amp;nbsp;=&amp;nbsp;0;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;formatSize(bytes)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(bytes&amp;nbsp;===&amp;nbsp;0)&amp;nbsp;return&amp;nbsp;&amp;#39;0&amp;nbsp;B&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;units&amp;nbsp;=&amp;nbsp;[&amp;#39;B&amp;#39;,&amp;nbsp;&amp;#39;KB&amp;#39;,&amp;nbsp;&amp;#39;MB&amp;#39;,&amp;nbsp;&amp;#39;GB&amp;#39;];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;unitIndex&amp;nbsp;=&amp;nbsp;Math.min(Math.floor(Math.log(bytes)&amp;nbsp;/&amp;nbsp;Math.log(1024)),&amp;nbsp;units.length&amp;nbsp;-&amp;nbsp;1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;`${(bytes&amp;nbsp;/&amp;nbsp;(1024&amp;nbsp;**&amp;nbsp;unitIndex)).toFixed(unitIndex&amp;nbsp;?&amp;nbsp;1&amp;nbsp;:&amp;nbsp;0)}&amp;nbsp;${units[unitIndex]}`;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;clearSelection()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(activeInput)&amp;nbsp;activeInput.value&amp;nbsp;=&amp;nbsp;&amp;#39;&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;activeInput&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fileList.replaceChildren();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result.hidden&amp;nbsp;=&amp;nbsp;true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;downloadFile(file)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;reader&amp;nbsp;=&amp;nbsp;new&amp;nbsp;FileReader();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;reader.addEventListener(&amp;#39;load&amp;#39;,&amp;nbsp;()&amp;nbsp;=&amp;gt;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;link&amp;nbsp;=&amp;nbsp;document.createElement(&amp;#39;a&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;link.href&amp;nbsp;=&amp;nbsp;reader.result;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;link.download&amp;nbsp;=&amp;nbsp;file.name&amp;nbsp;||&amp;nbsp;`文件_${Date.now()}`;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;document.body.appendChild(link);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;link.click();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;document.body.removeChild(link);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;});
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;reader.addEventListener(&amp;#39;error&amp;#39;,&amp;nbsp;()&amp;nbsp;=&amp;gt;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;resultTitle.textContent&amp;nbsp;=&amp;nbsp;&amp;#39;下载失败，请重试&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;});
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;reader.readAsDataURL(file);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;displayFiles(files,&amp;nbsp;input&amp;nbsp;=&amp;nbsp;null)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(!files.length)&amp;nbsp;return;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(activeInput&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;activeInput&amp;nbsp;!==&amp;nbsp;input)&amp;nbsp;activeInput.value&amp;nbsp;=&amp;nbsp;&amp;#39;&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;activeInput&amp;nbsp;=&amp;nbsp;input;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;resultTitle.textContent&amp;nbsp;=&amp;nbsp;files.length&amp;nbsp;&amp;gt;&amp;nbsp;1&amp;nbsp;?&amp;nbsp;`${files.length}&amp;nbsp;个文件处理完成`&amp;nbsp;:&amp;nbsp;&amp;#39;处理完成&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fileList.replaceChildren(...files.map((file)&amp;nbsp;=&amp;gt;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;item&amp;nbsp;=&amp;nbsp;document.createElement(&amp;#39;li&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;info&amp;nbsp;=&amp;nbsp;document.createElement(&amp;#39;span&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;name&amp;nbsp;=&amp;nbsp;document.createElement(&amp;#39;span&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;size&amp;nbsp;=&amp;nbsp;document.createElement(&amp;#39;span&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;downloadButton&amp;nbsp;=&amp;nbsp;document.createElement(&amp;#39;button&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;info.className&amp;nbsp;=&amp;nbsp;&amp;#39;file-info&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name.className&amp;nbsp;=&amp;nbsp;&amp;#39;file-name&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;name.textContent&amp;nbsp;=&amp;nbsp;file.name;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;size.className&amp;nbsp;=&amp;nbsp;&amp;#39;file-size&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;size.textContent&amp;nbsp;=&amp;nbsp;formatSize(file.size);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;downloadButton.className&amp;nbsp;=&amp;nbsp;&amp;#39;download-button&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;downloadButton.type&amp;nbsp;=&amp;nbsp;&amp;#39;button&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;downloadButton.textContent&amp;nbsp;=&amp;nbsp;&amp;#39;↓&amp;nbsp;下载&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;downloadButton.addEventListener(&amp;#39;click&amp;#39;,&amp;nbsp;()&amp;nbsp;=&amp;gt;&amp;nbsp;downloadFile(file));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;info.append(name,&amp;nbsp;size);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;item.append(info,&amp;nbsp;downloadButton);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;item;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result.hidden&amp;nbsp;=&amp;nbsp;false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;result.scrollIntoView({&amp;nbsp;behavior:&amp;nbsp;&amp;#39;smooth&amp;#39;,&amp;nbsp;block:&amp;nbsp;&amp;#39;nearest&amp;#39;&amp;nbsp;});
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;stopMicrophone()&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(recordingTimer)&amp;nbsp;clearInterval(recordingTimer);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recordingTimer&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;isRecording&amp;nbsp;=&amp;nbsp;false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(recordingProcessor)&amp;nbsp;recordingProcessor.disconnect();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(recordingSource)&amp;nbsp;recordingSource.disconnect();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(recordingGain)&amp;nbsp;recordingGain.disconnect();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recordingProcessor&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recordingSource&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recordingGain&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(microphoneStream)&amp;nbsp;microphoneStream.getTracks().forEach((track)&amp;nbsp;=&amp;gt;&amp;nbsp;track.stop());
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;microphoneStream&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(recordingAudioContext&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;recordingAudioContext.state&amp;nbsp;!==&amp;nbsp;&amp;#39;closed&amp;#39;)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recordingAudioContext.close().catch(()&amp;nbsp;=&amp;gt;&amp;nbsp;{});
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recordingAudioContext&amp;nbsp;=&amp;nbsp;null;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;createWavFile(chunks,&amp;nbsp;sampleCount,&amp;nbsp;sampleRate)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;buffer&amp;nbsp;=&amp;nbsp;new&amp;nbsp;ArrayBuffer(44&amp;nbsp;+&amp;nbsp;sampleCount&amp;nbsp;*&amp;nbsp;2);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;view&amp;nbsp;=&amp;nbsp;new&amp;nbsp;DataView(buffer);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;writeText(offset,&amp;nbsp;text)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;(let&amp;nbsp;index&amp;nbsp;=&amp;nbsp;0;&amp;nbsp;index&amp;nbsp;&amp;lt;&amp;nbsp;text.length;&amp;nbsp;index&amp;nbsp;+=&amp;nbsp;1)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;view.setUint8(offset&amp;nbsp;+&amp;nbsp;index,&amp;nbsp;text.charCodeAt(index));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writeText(0,&amp;nbsp;&amp;#39;RIFF&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;view.setUint32(4,&amp;nbsp;36&amp;nbsp;+&amp;nbsp;sampleCount&amp;nbsp;*&amp;nbsp;2,&amp;nbsp;true);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writeText(8,&amp;nbsp;&amp;#39;WAVE&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writeText(12,&amp;nbsp;&amp;#39;fmt&amp;nbsp;&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;view.setUint32(16,&amp;nbsp;16,&amp;nbsp;true);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;view.setUint16(20,&amp;nbsp;1,&amp;nbsp;true);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;view.setUint16(22,&amp;nbsp;1,&amp;nbsp;true);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;view.setUint32(24,&amp;nbsp;sampleRate,&amp;nbsp;true);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;view.setUint32(28,&amp;nbsp;sampleRate&amp;nbsp;*&amp;nbsp;2,&amp;nbsp;true);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;view.setUint16(32,&amp;nbsp;2,&amp;nbsp;true);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;view.setUint16(34,&amp;nbsp;16,&amp;nbsp;true);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;writeText(36,&amp;nbsp;&amp;#39;data&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;view.setUint32(40,&amp;nbsp;sampleCount&amp;nbsp;*&amp;nbsp;2,&amp;nbsp;true);

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;let&amp;nbsp;offset&amp;nbsp;=&amp;nbsp;44;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;chunks.forEach((chunk)&amp;nbsp;=&amp;gt;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;(let&amp;nbsp;index&amp;nbsp;=&amp;nbsp;0;&amp;nbsp;index&amp;nbsp;&amp;lt;&amp;nbsp;chunk.length;&amp;nbsp;index&amp;nbsp;+=&amp;nbsp;1)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;sample&amp;nbsp;=&amp;nbsp;Math.max(-1,&amp;nbsp;Math.min(1,&amp;nbsp;chunk[index]));
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;view.setInt16(offset,&amp;nbsp;sample&amp;nbsp;&amp;lt;&amp;nbsp;0&amp;nbsp;?&amp;nbsp;sample&amp;nbsp;*&amp;nbsp;0x8000&amp;nbsp;:&amp;nbsp;sample&amp;nbsp;*&amp;nbsp;0x7fff,&amp;nbsp;true);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;offset&amp;nbsp;+=&amp;nbsp;2;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;});

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;new&amp;nbsp;File([buffer],&amp;nbsp;`recording-${Date.now()}.wav`,&amp;nbsp;{&amp;nbsp;type:&amp;nbsp;&amp;#39;audio/wav&amp;#39;&amp;nbsp;});
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;inputs.forEach((input)&amp;nbsp;=&amp;gt;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;input.addEventListener(&amp;#39;change&amp;#39;,&amp;nbsp;()&amp;nbsp;=&amp;gt;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;files&amp;nbsp;=&amp;nbsp;Array.from(input.files&amp;nbsp;||&amp;nbsp;[]);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;displayFiles(files,&amp;nbsp;input);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;});
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;});

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;openRecorder.addEventListener(&amp;#39;click&amp;#39;,&amp;nbsp;()&amp;nbsp;=&amp;gt;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recorderPanel.hidden&amp;nbsp;=&amp;nbsp;false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recorderPanel.scrollIntoView({&amp;nbsp;behavior:&amp;nbsp;&amp;#39;smooth&amp;#39;,&amp;nbsp;block:&amp;nbsp;&amp;#39;nearest&amp;#39;&amp;nbsp;});
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;});

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;startRecording.addEventListener(&amp;#39;click&amp;#39;,&amp;nbsp;async&amp;nbsp;()&amp;nbsp;=&amp;gt;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;AudioContextClass&amp;nbsp;=&amp;nbsp;window.AudioContext&amp;nbsp;||&amp;nbsp;window.webkitAudioContext;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(!navigator.mediaDevices?.getUserMedia&amp;nbsp;||&amp;nbsp;!AudioContextClass)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recorderStatus.textContent&amp;nbsp;=&amp;nbsp;&amp;#39;当前浏览器不支持网页录音，请使用下方按钮选择已有音频。&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;microphoneStream&amp;nbsp;=&amp;nbsp;await&amp;nbsp;navigator.mediaDevices.getUserMedia({
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;audio:&amp;nbsp;{&amp;nbsp;channelCount:&amp;nbsp;1,&amp;nbsp;echoCancellation:&amp;nbsp;true,&amp;nbsp;noiseSuppression:&amp;nbsp;true&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;});
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recordingAudioContext&amp;nbsp;=&amp;nbsp;new&amp;nbsp;AudioContextClass();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;await&amp;nbsp;recordingAudioContext.resume();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recordingSource&amp;nbsp;=&amp;nbsp;recordingAudioContext.createMediaStreamSource(microphoneStream);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recordingProcessor&amp;nbsp;=&amp;nbsp;recordingAudioContext.createScriptProcessor(4096,&amp;nbsp;1,&amp;nbsp;1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recordingGain&amp;nbsp;=&amp;nbsp;recordingAudioContext.createGain();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recordingGain.gain.value&amp;nbsp;=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pcmChunks&amp;nbsp;=&amp;nbsp;[];
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pcmSampleCount&amp;nbsp;=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;isRecording&amp;nbsp;=&amp;nbsp;true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recordingProcessor.onaudioprocess&amp;nbsp;=&amp;nbsp;(event)&amp;nbsp;=&amp;gt;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(!isRecording)&amp;nbsp;return;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;samples&amp;nbsp;=&amp;nbsp;new&amp;nbsp;Float32Array(event.inputBuffer.length);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;event.inputBuffer.copyFromChannel(samples,&amp;nbsp;0);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pcmChunks.push(samples);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pcmSampleCount&amp;nbsp;+=&amp;nbsp;samples.length;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;};
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recordingSource.connect(recordingProcessor);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recordingProcessor.connect(recordingGain);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recordingGain.connect(recordingAudioContext.destination);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recordingStartedAt&amp;nbsp;=&amp;nbsp;Date.now();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recorderStatus.textContent&amp;nbsp;=&amp;nbsp;&amp;#39;正在录音&amp;nbsp;00:00&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recordingTimer&amp;nbsp;=&amp;nbsp;setInterval(()&amp;nbsp;=&amp;gt;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;elapsed&amp;nbsp;=&amp;nbsp;Math.floor((Date.now()&amp;nbsp;-&amp;nbsp;recordingStartedAt)&amp;nbsp;/&amp;nbsp;1000);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;minutes&amp;nbsp;=&amp;nbsp;String(Math.floor(elapsed&amp;nbsp;/&amp;nbsp;60)).padStart(2,&amp;nbsp;&amp;#39;0&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;seconds&amp;nbsp;=&amp;nbsp;String(elapsed&amp;nbsp;%&amp;nbsp;60).padStart(2,&amp;nbsp;&amp;#39;0&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recorderStatus.textContent&amp;nbsp;=&amp;nbsp;`正在录音&amp;nbsp;${minutes}:${seconds}`;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;},&amp;nbsp;1000);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;startRecording.disabled&amp;nbsp;=&amp;nbsp;true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stopRecording.disabled&amp;nbsp;=&amp;nbsp;false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&amp;nbsp;catch&amp;nbsp;(error)&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stopMicrophone();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;insecure&amp;nbsp;=&amp;nbsp;!window.isSecureContext;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recorderStatus.textContent&amp;nbsp;=&amp;nbsp;insecure
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;?&amp;nbsp;&amp;#39;浏览器只允许&amp;nbsp;HTTPS&amp;nbsp;页面使用麦克风，请通过&amp;nbsp;HTTPS&amp;nbsp;打开本页。&amp;#39;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;&amp;#39;未能使用麦克风，请检查浏览器的网站麦克风权限。&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;});

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stopRecording.addEventListener(&amp;#39;click&amp;#39;,&amp;nbsp;()&amp;nbsp;=&amp;gt;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(!isRecording&amp;nbsp;||&amp;nbsp;!recordingAudioContext&amp;nbsp;||&amp;nbsp;!pcmSampleCount)&amp;nbsp;return;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;isRecording&amp;nbsp;=&amp;nbsp;false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;sampleRate&amp;nbsp;=&amp;nbsp;recordingAudioContext.sampleRate;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;duration&amp;nbsp;=&amp;nbsp;pcmSampleCount&amp;nbsp;/&amp;nbsp;sampleRate;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;recording&amp;nbsp;=&amp;nbsp;createWavFile(pcmChunks,&amp;nbsp;pcmSampleCount,&amp;nbsp;sampleRate);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stopMicrophone();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;displayFiles([recording]);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;recorderStatus.textContent&amp;nbsp;=&amp;nbsp;`录音处理完成（${duration.toFixed(1)}&amp;nbsp;秒），可在下方下载。`;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;startRecording.disabled&amp;nbsp;=&amp;nbsp;false;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stopRecording.disabled&amp;nbsp;=&amp;nbsp;true;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;});

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;clearButton.addEventListener(&amp;#39;click&amp;#39;,&amp;nbsp;clearSelection);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;window.addEventListener(&amp;#39;pagehide&amp;#39;,&amp;nbsp;()&amp;nbsp;=&amp;gt;&amp;nbsp;{
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stopMicrophone();
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;});
&amp;nbsp;&amp;nbsp;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;p&gt;页面中的拍照和录像入口可以分别使用带有 &lt;code&gt;capture&lt;/code&gt; 属性的文件控件。拍照入口设置 &lt;code&gt;accept=&amp;quot;image/*&amp;quot;&lt;/code&gt;，录像入口设置 &lt;code&gt;accept=&amp;quot;video/*&amp;quot;&lt;/code&gt;，安卓APP会根据文件类型打开对应的系统采集页面。&lt;/p&gt;&lt;p&gt;拍摄照片：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-html&quot;&gt;&amp;lt;input&amp;nbsp;type=&amp;quot;file&amp;quot;&amp;nbsp;accept=&amp;quot;image/*&amp;quot;&amp;nbsp;capture=&amp;quot;environment&amp;quot;&amp;nbsp;/&amp;gt;&lt;/pre&gt;&lt;p&gt;录制视频：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-html&quot;&gt;&amp;lt;input&amp;nbsp;type=&amp;quot;file&amp;quot;&amp;nbsp;accept=&amp;quot;video/*&amp;quot;&amp;nbsp;capture=&amp;quot;environment&amp;quot;&amp;nbsp;/&amp;gt;&lt;/pre&gt;&lt;p&gt;音频录制可以通过 &lt;code&gt;navigator.mediaDevices.getUserMedia()&lt;/code&gt; 获取麦克风音频流，再使用浏览器音频接口处理并生成音频文件。普通文件入口不设置 &lt;code&gt;capture&lt;/code&gt;，因此会保留系统提供的文件、照片和视频选择方式。&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1786193047247_0340306a.png&quot; alt=&quot;拍照录像录音和文件选择页面&quot;/&gt;&lt;/p&gt;&lt;h2&gt;打包APK并配置权限&lt;/h2&gt;&lt;p&gt;打开HTML一键打包APK工具，选择包含 &lt;code&gt;index.html&lt;/code&gt; 的项目目录，填写应用名称、包名等打包信息。&lt;/p&gt;&lt;p&gt;在权限设置中勾选“相机权限”和“麦克风权限”：&lt;/p&gt;&lt;ul class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;相机权限用于拍摄照片、录制视频以及网页调用摄像头。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;麦克风权限用于网页录音；录制带声音的视频时也需要该权限。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;普通文件选择通过安卓系统文件选择器完成，用户只会授权当前选择的文件。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1786193047821_97366786.png&quot; alt=&quot;打包APK时配置相机和麦克风权限&quot;/&gt;&lt;/p&gt;&lt;p&gt;确认配置后开始打包，等待工具生成APK文件。&lt;/p&gt;&lt;h2&gt;安装并测试功能&lt;/h2&gt;&lt;p&gt;将生成的APK安装到安卓手机，依次测试页面中的四个入口：&lt;/p&gt;&lt;ol class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;点击“拍摄照片”，确认APP直接打开相机拍照页面。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;点击“录制视频”，确认APP直接打开视频录制页面，并且能够正常保存视频。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;点击“录制音频”，首次使用时允许APP访问麦克风，停止录音后确认页面能够显示并下载录音文件。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;点击“选择文件”，确认系统文件选择界面正常打开，并且可以选择一个或多个文件。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;不同品牌手机使用的相机和文件管理应用可能不同，因此系统界面的样式会有差异。&lt;code&gt;capture&lt;/code&gt; 属性用于告诉安卓当前需要拍照还是录像，但最终的采集界面由手机系统和默认相机应用提供。&lt;/p&gt;&lt;p&gt;如果拍照或录像入口没有打开对应页面，请先检查APP的相机权限；如果网页无法开始录音，请检查麦克风权限。对于在线页面，网页录音通常还要求通过HTTPS加载；打包到APP内的本地页面则由WebView和APP权限共同控制。&lt;/p&gt;</description><pubDate>Sat, 08 Aug 2026 20:44:05 +0800</pubDate></item><item><title>HTML项目打包APK：二维码扫码功能实现</title><link>https://www.ylongsoft.com/post/html-apk-qrcode-scanner-ylongsoft.html</link><description>&lt;p&gt;在HTML项目中，可以使用 &lt;code&gt;html5-qrcode&lt;/code&gt; 调用手机摄像头并识别二维码。完成页面代码后，再通过HTML一键打包APK工具勾选相机权限，即可生成支持扫码的安卓APP。&lt;/p&gt;
&lt;p&gt;如果你不了解HTML打包APK工具, 想要进一步了解, 可以查看官网:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://html2apk.leapever.com/&quot;&gt;HTML一键打包APK工具官网&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;创建扫码页面&lt;/h2&gt;
&lt;p&gt;在HTML项目入口目录中创建 &lt;code&gt;index.html&lt;/code&gt;，写入以下代码。页面点击“开始扫码”后会申请摄像头权限，识别成功时停止摄像头并显示二维码内容。&lt;/p&gt;
&lt;pre class=&quot;prism-highlight prism-language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!doctype html&amp;gt;
&amp;lt;html lang=&amp;quot;zh-CN&amp;quot;&amp;gt;
    &amp;lt;head&amp;gt;
        &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot; /&amp;gt;
        &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1, viewport-fit=cover&amp;quot; /&amp;gt;
        &amp;lt;title&amp;gt;二维码扫码&amp;lt;/title&amp;gt;
        &amp;lt;script src=&amp;quot;https://unpkg.com/html5-qrcode@2.3.8/html5-qrcode.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
        &amp;lt;style&amp;gt;
            * {
                box-sizing: border-box;
            }

            body {
                min-height: 100vh;
                margin: 0;
                padding: 20px;
                display: grid;
                place-items: center;
                font-family: 'Microsoft YaHei', sans-serif;
                background: #f4f7f5;
                color: #17221c;
            }

            main {
                width: min(100%, 440px);
            }

            h1 {
                margin: 0 0 8px;
                font-size: 30px;
            }

            p {
                margin: 0 0 18px;
                color: #526159;
            }

            #reader {
                width: 100%;
                min-height: 280px;
                overflow: hidden;
                border: 1px solid #cad4ce;
                border-radius: 8px;
                background: #101511;
            }

            #reader video {
                object-fit: cover;
            }

            .actions {
                display: grid;
                grid-template-columns: 1fr 1fr;
                gap: 10px;
                margin-top: 14px;
            }

            button {
                min-height: 48px;
                border: 0;
                border-radius: 6px;
                padding: 0 16px;
                font: inherit;
                font-weight: 700;
            }

            #startButton {
                background: #197447;
                color: white;
            }

            #stopButton {
                background: #dfe6e2;
                color: #26352d;
            }

            button:disabled {
                opacity: 0.5;
            }

            #status {
                min-height: 24px;
                margin-top: 12px;
                font-size: 14px;
                color: #526159;
            }
        &amp;lt;/style&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;main&amp;gt;
            &amp;lt;h1&amp;gt;二维码扫码&amp;lt;/h1&amp;gt;
            &amp;lt;p&amp;gt;点击开始后，将摄像头对准二维码。&amp;lt;/p&amp;gt;
            &amp;lt;div id=&amp;quot;reader&amp;quot; aria-label=&amp;quot;摄像头扫码区域&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
            &amp;lt;div class=&amp;quot;actions&amp;quot;&amp;gt;
                &amp;lt;button id=&amp;quot;startButton&amp;quot; type=&amp;quot;button&amp;quot;&amp;gt;开始扫码&amp;lt;/button&amp;gt;
                &amp;lt;button id=&amp;quot;stopButton&amp;quot; type=&amp;quot;button&amp;quot; disabled&amp;gt;停止扫码&amp;lt;/button&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div id=&amp;quot;status&amp;quot; role=&amp;quot;status&amp;quot;&amp;gt;等待开始&amp;lt;/div&amp;gt;
        &amp;lt;/main&amp;gt;

        &amp;lt;script&amp;gt;
            const reader = new Html5Qrcode('reader');
            const startButton = document.getElementById('startButton');
            const stopButton = document.getElementById('stopButton');
            const status = document.getElementById('status');
            let isScanning = false;
            let resultHandled = false;

            async function stopScanning() {
                if (!isScanning) return;

                await reader.stop();
                isScanning = false;
                startButton.disabled = false;
                stopButton.disabled = true;
                status.textContent = '扫码已停止';
            }

            async function startScanning() {
                startButton.disabled = true;
                status.textContent = '正在请求摄像头权限...';
                resultHandled = false;

                try {
                    await reader.start(
                        { facingMode: 'environment' },
                        { fps: 10, qrbox: { width: 240, height: 240 } },
                        async decodedText =&amp;gt; {
                            if (resultHandled) return;
                            resultHandled = true;
                            await stopScanning();
                            alert(decodedText);
                        },
                        () =&amp;gt; {}
                    );

                    isScanning = true;
                    stopButton.disabled = false;
                    status.textContent = '正在扫描...';
                } catch (error) {
                    startButton.disabled = false;
                    status.textContent = '无法打开摄像头，请检查相机权限。';
                    console.error(error);
                }
            }

            startButton.addEventListener('click', startScanning);
            stopButton.addEventListener('click', () =&amp;gt; {
                stopScanning().catch(console.error);
            });

            window.addEventListener('pagehide', () =&amp;gt; {
                if (isScanning) reader.stop().catch(() =&amp;gt; {});
            });
        &amp;lt;/script&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;示例通过 CDN 加载 &lt;code&gt;html5-qrcode&lt;/code&gt;。如果APP需要完全离线运行，请提前下载 &lt;code&gt;html5-qrcode.min.js&lt;/code&gt; 放入项目目录，并将页面中的脚本地址改为本地相对路径。&lt;/p&gt;
&lt;h2&gt;打包APK并勾选相机权限&lt;/h2&gt;
&lt;p&gt;打开HTML一键打包APK工具，选择包含 &lt;code&gt;index.html&lt;/code&gt; 的项目目录，填写应用名称、包名等打包信息。在权限设置中勾选“相机权限”，否则APP无法调用手机摄像头。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1786109167556_c6b01d9d.png&quot; alt=&quot;打包APK时勾选相机权限&quot;&gt;&lt;/p&gt;
&lt;p&gt;确认配置后开始打包，等待工具生成APK文件。&lt;/p&gt;
&lt;h2&gt;安装并测试扫码&lt;/h2&gt;
&lt;p&gt;将生成的APK安装到安卓手机。首次点击“开始扫码”时，系统会弹出相机授权提示，选择允许后，将摄像头对准二维码。识别成功后，页面会停止扫描并弹出二维码中的文字或链接。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1786109167967_a2eb5094.png&quot; alt=&quot;打包后的APP扫码运行效果&quot;&gt;&lt;/p&gt;
&lt;p&gt;如果页面提示无法打开摄像头，请先在手机的应用权限设置中确认相机权限已经允许。扫码页面使用 CDN 脚本时，还需要确保手机能够正常访问网络；改用本地脚本后则不受此限制。&lt;/p&gt;
</description><pubDate>Fri, 07 Aug 2026 21:26:06 +0800</pubDate></item><item><title>C#混淆选项选择指南：恒盾加密大师详解</title><link>https://www.ylongsoft.com/post/csharp-obfuscator-options-guide.html</link><description>&lt;p&gt;恒盾C#混淆加密大师提供了基本保护、垃圾代码注入、代码混淆和重命名等多类选项。这些功能面向不同的攻击场景：部分用于阻止调试和反编译工具；另一些增加反编译代码理解难度；还有直接改变类型、函数和字段的命名。&lt;/p&gt;
&lt;p&gt;实际选用时，无需不加区分地启用全部选项。更合理的做法是先理解每类功能的作用域，再根据项目类型（DLL、控制台程序、WinForms、WPF等）逐步启用，并在每次调整后完成启动和核心功能测试。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785844596803_dc34a40c.png&quot; alt=&quot;界面&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://csharpobf.leapever.com/&quot;&gt;官方网址&lt;/a&gt;&lt;/p&gt;
&lt;!-- truncate --&gt;
&lt;h2&gt;四类混淆选项分别解决什么问题&lt;/h2&gt;
&lt;p&gt;软件中的选项可划分为四类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;基本保护选项&lt;/strong&gt;：针对调试器、反编译工具、程序篡改和虚拟机运行环境进行防护。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注入功能选项&lt;/strong&gt;：向程序集注入无用字段、指令、函数、类型或字符串，增加静态分析干扰。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;混淆功能选项&lt;/strong&gt;：改变代码、数据或程序集结构，使反编译结果更难还原。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重命名选项&lt;/strong&gt;：修改Module、字段、函数、命名空间、参数、类型和Assembly等标识符。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这四类功能可以灵活组合：重命名负责降低代码可读性；字符串和流程类选项保护关键逻辑；基本保护针对常见分析工具和运行环境形成额外防线。&lt;/p&gt;
&lt;h2&gt;基本保护选项&lt;/h2&gt;
&lt;p&gt;基本保护主要面向调试、反编译、篡改和运行环境检测。部分功能在检测到特定行为时会终止程序，因此启用后需在目标用户真实环境中测试。&lt;/p&gt;
&lt;h3&gt;防调试、防DnSpy与防断点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;防调试&lt;/strong&gt;：检测Visual Studio或其他调试工具附加行为，发现后自动退出。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;防DnSpy&lt;/strong&gt;：针对DnSpy动态调试检测，发现后退出。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;防断点&lt;/strong&gt;：检测程序运行中异常超长停顿，防止通过断点跟踪代码。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这三个选项与运行时分析相关，适合保护授权校验、关键算法和商业逻辑。由于性能较弱的设备或特殊环境可能影响检测效果，建议先在测试版启用，再覆盖不同配置设备验证。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785844597452_41a148c9.png&quot; alt=&quot;防DnSpy处理效果&quot;&gt;&lt;/p&gt;
&lt;h3&gt;防ILDasm、防ILSpy与防de4dot&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;防ILDasm&lt;/strong&gt;：阻止系统ILDasm正常反编译处理后的DLL或EXE。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;防ILSpy&lt;/strong&gt;：让处理后程序集无法被ILSpy正常解析。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;防de4dot&lt;/strong&gt;：干扰de4dot自动反混淆。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这组功能用于阻止常见静态分析和自动还原工具。可与重命名、流程混淆、字符串加密搭配，让分析者难以打开程序集，也难以理解已反编译代码。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785844597835_360c19a7.png&quot; alt=&quot;防ILDasm处理效果&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785844598040_1f85bf03.png&quot; alt=&quot;防de4dot处理效果&quot;&gt;&lt;/p&gt;
&lt;h3&gt;防篡改与加壳&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;防篡改（仅限EXE）&lt;/strong&gt;：校验EXE是否被修改，改动后无法运行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;加壳（仅限EXE）&lt;/strong&gt;：加密原生程序到外层EXE，避免静态反编译。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;仅适用于EXE。防篡改适合需保证文件完整性的桌面程序；加壳适合整体隐藏原始程序集。处理后需检查数字签名、杀毒兼容性及更新流程。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785844598260_977664ab.png&quot; alt=&quot;EXE加壳处理效果&quot;&gt;&lt;/p&gt;
&lt;h3&gt;防虚拟机&lt;/h3&gt;
&lt;p&gt;防虚拟机检测程序是否运行在虚拟机中，检测到后停止运行。适合禁止虚拟机运行的应用，但不适合云桌面、虚拟化服务器、自动化测试或沙箱环境。启用前需确认用户部署环境，若正常客户可能使用VMware、Hyper-V等，建议谨慎。&lt;/p&gt;
&lt;h2&gt;注入功能选项&lt;/h2&gt;
&lt;p&gt;注入功能通过增加干扰内容，让反编译后程序集结构更复杂，而非替代关键代码加密。&lt;/p&gt;
&lt;h3&gt;垃圾域、垃圾函数与垃圾类型&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;垃圾域&lt;/strong&gt;：向类型中注入大量无用字段。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;垃圾函数&lt;/strong&gt;：注入不参与业务的函数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;垃圾类型&lt;/strong&gt;：注入额外类型。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些选项让反编译工具显示更多成员和类型，增加定位真实业务代码的难度。对体积敏感项目需比较处理前后文件大小和加载表现。&lt;/p&gt;
&lt;h3&gt;垃圾空指令与垃圾字符串&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;垃圾空指令&lt;/strong&gt;：在IL指令中注入无用指令，增加阅读难度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;垃圾字符串&lt;/strong&gt;：注入无用字符串，干扰基于字符串搜索的定位。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;垃圾空指令适合配合流程混淆；垃圾字符串干扰接口地址、提示文本或关键字检索。主要增加分析成本。&lt;/p&gt;
&lt;h2&gt;混淆功能选项&lt;/h2&gt;
&lt;p&gt;混淆功能处理程序集信息、代码流程、常量、调用关系等。一些选项影响较大，建议从常用选项开始逐步增加强度。&lt;/p&gt;
&lt;h3&gt;程序集与文件结构混淆&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;文件信息混淆&lt;/strong&gt;：修改程序内部名称、Assembly信息。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文件时间混淆&lt;/strong&gt;：修改加密文件时间戳。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DOS头混淆&lt;/strong&gt;：修改EXE的DOS头，去除常见可识别字符串。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;混淆引用列表&lt;/strong&gt;：处理程序集引用列表，使依赖关系更模糊。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;加密资源文件&lt;/strong&gt;：加密程序集中的资源，防止直接查看。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;若程序依赖程序集名称、文件版本、反射、插件扫描或资源加载路径，需重点验证。加密资源文件还需测试图片、语言资源等能否正常读取。&lt;/p&gt;
&lt;h3&gt;流程与函数调用混淆&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;流程混淆&lt;/strong&gt;：打乱函数内部指令并增加跳转，使控制流程难以理解。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;函数调用混淆&lt;/strong&gt;：通过函数token调用目标函数，降低可读性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;链式函数混淆&lt;/strong&gt;：将一次调用转为多层嵌套调用，增加分析难度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异步混淆&lt;/strong&gt;：将部分代码转换为异步调用形式，使静态跟踪更困难。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错误函数体混淆&lt;/strong&gt;：加入错误指令，干扰静态分析工具解析函数体。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;流程混淆是核心算法保护的首选。函数调用、链式和异步混淆进一步改变结构，适合不依赖特殊调用顺序的业务代码。对UI线程、启动入口、COM调用、反射调用等需逐项测试。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785844598480_e7f65e34.png&quot; alt=&quot;流程混淆前后对比&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785844598703_7d0947f6.png&quot; alt=&quot;函数调用混淆效果&quot;&gt;&lt;/p&gt;
&lt;h3&gt;字符串保护&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;字符串加密&lt;/strong&gt;：加密字符串，避免静态分析直接找到关键文本。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;字符串拆分&lt;/strong&gt;：将完整字符串拆成多个组合，降低搜索效率。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;字符串隐藏&lt;/strong&gt;：加密后存放到原生函数，使反编译工具无法获取值。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;字符串加密适合保护接口地址、协议字段、算法参数；拆分可干扰简单检索；隐藏强度更高，适合少量重要字符串。配置文件中的密码、令牌需用专门密钥管理方案。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785844598917_70fe88f8.png&quot; alt=&quot;字符串加密效果&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785844599129_9039d35a.png&quot; alt=&quot;字符串拆分效果&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785844599333_fbc0f121.png&quot; alt=&quot;字符串隐藏效果&quot;&gt;&lt;/p&gt;
&lt;h3&gt;数字、布尔值与小数保护&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;布尔混淆&lt;/strong&gt;：将布尔值转为更难识别的基础类型表达。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数字混淆&lt;/strong&gt;：将整型数字转化为复杂运算，隐藏常量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数字隐藏&lt;/strong&gt;：将整型数字加密存放到原生函数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;小数混淆&lt;/strong&gt;：加密代码中的小数，避免直接看到原始值。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;适合保护算法常量、状态标识、限制数值和业务参数。与流程混淆配合，静态分析难度更高。涉及浮点精度或高频计算的代码需重点验证。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785844599550_be995e0e.png&quot; alt=&quot;数字混淆效果&quot;&gt;&lt;/p&gt;
&lt;h3&gt;函数体隐藏与原生化EXE&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;函数体隐藏&lt;/strong&gt;：加密函数体，使反编译工具无法查看内部代码。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;原生化EXE&lt;/strong&gt;：将EXE转为原生程序，C#反编译工具无法分析IL。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;适合保护核心实现。函数体隐藏可加强保护重要算法；原生化EXE从整体改变程序形态，仅适用于EXE。启用后需完整测试启动、异常处理、依赖加载等。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785844599754_7b29091b.png&quot; alt=&quot;函数体隐藏效果&quot;&gt;&lt;/p&gt;
&lt;h2&gt;重命名选项&lt;/h2&gt;
&lt;p&gt;重命名是C#混淆中最直观的保护，将具有业务含义的标识符替换为难以理解的新名称，移除语义。&lt;/p&gt;
&lt;h3&gt;重命名模式怎么选&lt;/h3&gt;
&lt;p&gt;软件提供五种模式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;字母数字模式&lt;/strong&gt;：字母数字组合，适合常规项目。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UUID模式&lt;/strong&gt;：长名称，增加阅读和检索难度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;特殊字符模式&lt;/strong&gt;：使用特殊字符，适合更高阅读干扰。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Base64模式&lt;/strong&gt;：Base64风格字符串。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;英文单词模式&lt;/strong&gt;：英文单词替换，表面可读但失去真实含义。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不同模式影响外观，不改变勾选对象。日常可从字母数字模式开始；若外部工具或日志系统对字符有限制，避免使用特殊字符模式。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785844599997_802d3c4b.png&quot; alt=&quot;字母数字重命名模式&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785844600232_0a9be64e.png&quot; alt=&quot;UUID重命名模式&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785844600437_f99ee60b.png&quot; alt=&quot;特殊字符重命名模式&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785844600642_c39f068d.png&quot; alt=&quot;Base64重命名模式&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785844600846_bc4a0eca.png&quot; alt=&quot;英文单词重命名模式&quot;&gt;&lt;/p&gt;
&lt;h3&gt;可以重命名哪些对象&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Module重命名&lt;/strong&gt;：修改全局Module名称。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;域重命名&lt;/strong&gt;：修改类中字段名称。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;函数重命名&lt;/strong&gt;：修改方法名称。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;命名空间重命名&lt;/strong&gt;：修改类型所在命名空间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数重命名&lt;/strong&gt;：修改函数参数名称。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;类型重命名&lt;/strong&gt;：修改类、结构体等类型名称。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Assembly重命名&lt;/strong&gt;：修改程序集名称。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;普通内部代码可优先启用字段、函数、参数和类型重命名。涉及反射、依赖注入、序列化、XAML等时，名称可能是运行时契约，需先确认。Assembly重命名影响依赖程序集、插件加载等，处理多个DLL时需验证引用解析。&lt;/p&gt;
&lt;h2&gt;不同项目可以怎样组合&lt;/h2&gt;
&lt;h3&gt;普通桌面程序&lt;/h3&gt;
&lt;p&gt;先启用函数、字段、参数和类型重命名，加入字符串加密、数字混淆和流程混淆。确认功能正常后，再根据需要增加防调试、防ILSpy、防DnSpy或加壳。&lt;/p&gt;
&lt;h3&gt;供第三方调用的类库&lt;/h3&gt;
&lt;p&gt;优先保护内部类型和实现。公开API、反射入口、序列化模型需谨慎重命名，否则可能导致调用方无法找到成员。字符串加密、流程混淆和函数体隐藏可保护不对外暴露的核心逻辑。&lt;/p&gt;
&lt;h3&gt;包含重要算法的EXE&lt;/h3&gt;
&lt;p&gt;组合流程混淆、字符串隐藏、数字隐藏、函数调用混淆和函数体隐藏。完成兼容性测试后，考虑加壳、防篡改或原生化EXE。高强度选项应逐项增加并保留测试结果。&lt;/p&gt;
&lt;h2&gt;推荐的启用和测试顺序&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;保留原始DLL或EXE，准备覆盖核心功能的测试用例。&lt;/li&gt;
&lt;li&gt;先启用字段、函数、参数和类型重命名，验证程序启动及运行。&lt;/li&gt;
&lt;li&gt;加入字符串加密、数字混淆和流程混淆，检查核心业务结果和性能。&lt;/li&gt;
&lt;li&gt;按需启用垃圾代码注入和反编译工具防护。&lt;/li&gt;
&lt;li&gt;最后测试函数体隐藏、加壳、原生化EXE等大范围选项。&lt;/li&gt;
&lt;li&gt;每增加一组功能都重新测试启动、登录、配置读写、网络请求等。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;若出现异常，可回退到上一个可用组合再逐个启用。&lt;/p&gt;
&lt;h2&gt;使用时需要注意什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;保护强度越高并不代表越适合所有项目，稳定运行是前提。&lt;/li&gt;
&lt;li&gt;依赖反射、序列化、XAML、插件机制等项目，需重点测试重命名兼容性。&lt;/li&gt;
&lt;li&gt;防篡改、加壳和原生化EXE仅限EXE，不能用于DLL。&lt;/li&gt;
&lt;li&gt;防虚拟机可能影响云桌面、虚拟化服务器中的正常用户。&lt;/li&gt;
&lt;li&gt;处理后文件应在目标操作系统、架构和性能配置上验证。&lt;/li&gt;
&lt;li&gt;混淆用于提高逆向成本，不能替代权限控制、签名校验、密钥管理和服务端安全。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;恒盾C#混淆加密大师各类选项承担不同作用：基本保护应对调试和反编译工具；注入功能增加干扰；混淆功能隐藏代码流程和关键数据；重命名移除业务语义。&lt;/p&gt;
&lt;p&gt;对多数项目，可从重命名、字符串加密、数字混淆和流程混淆开始，再根据程序类型增加防调试、工具防护、函数体隐藏、加壳或原生化EXE。逐步启用、逐步测试，在保护强度和兼容性之间取得平衡。&lt;/p&gt;
</description><pubDate>Tue, 04 Aug 2026 19:56:39 +0800</pubDate></item><item><title>C#混淆随机种子的作用与使用教程</title><link>https://www.ylongsoft.com/post/csharp-obfuscator-random-seed-guide-zblog-ylongsoft.html</link><description>&lt;p&gt;在混淆 C# 应用时，很多开发者会发现，即使输入文件和配置一模一样，每次生成的结果也可能不同。这是因为恒盾C#混淆加密大师默认引入了随机性，避免每次构建都产生完全相同的结果。但在某些场景下——比如排查问题、做回归测试、或者对接 CI/CD 流程——我们反而希望结果是可复现的，以便对比和定位。&lt;/p&gt;
&lt;p&gt;这时，随机种子就派上用场了。它本质上是一个控制混淆过程随机行为的开关。填上一个固定的值后，对于同一个 EXE 或 DLL，在配置完全一致的情况下，每次处理都会得到相同的结果；如果不填，软件就会自动随机处理，保持构建之间的差异。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.ylongsoft.com/zb_users/upload/2026/08/1785763880134_c7a11028.png&quot; alt=&quot;恒盾C#混淆加密大师随机种子配置&quot;&gt;&lt;/p&gt;
&lt;h2&gt;随机种子有什么作用&lt;/h2&gt;
&lt;p&gt;随机种子让开发者可以在“可复现的结果”和“每次结果随机”之间灵活选择。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;填写固定种子&lt;/strong&gt;：适用于重复构建、对比结果、排查问题，或者需要保持发布流程一致。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;留空不填&lt;/strong&gt;：软件自动随机，适用于希望不同构建产生不同混淆结果的日常发布。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;需要特别注意：随机种子不会改变你启用了哪些保护功能，也不会替代字符串加密、流程混淆或重命名。它只影响结果是否容易复现。&lt;/p&gt;
&lt;h2&gt;哪些场景适合设置固定种子&lt;/h2&gt;
&lt;h3&gt;1. 排查混淆后的运行问题&lt;/h3&gt;
&lt;p&gt;如果程序在混淆后出现异常，保留输入文件、配置和随机种子，重新处理一次。固定种子能减少重复测试时的结果差异，让问题更容易定位。&lt;/p&gt;
&lt;h3&gt;2. 进行版本回归测试&lt;/h3&gt;
&lt;p&gt;在同一个版本上反复验证启动、登录、授权、读写等核心功能时，固定种子可以提供更稳定的测试条件，方便对比不同保护选项的效果。&lt;/p&gt;
&lt;h3&gt;3. 接入自动化构建和 CI/CD&lt;/h3&gt;
&lt;p&gt;将混淆步骤集成到构建脚本或持续集成流水线中后，为项目指定固定种子，可以让开发机、构建机和流水线使用相同的条件，便于复现和排错。&lt;/p&gt;
&lt;h3&gt;4. 团队共享混淆配置&lt;/h3&gt;
&lt;p&gt;多人维护同一个项目时，把随机种子和其他选项一起保存到配置文件里，团队成员加载统一配置后，就能减少因随机结果带来的额外沟通成本。&lt;/p&gt;
&lt;h3&gt;5. 保存可复现的发布记录&lt;/h3&gt;
&lt;p&gt;对于重要版本，把当次使用的输入文件、配置、软件版本和种子一起归档。以后要回溯或者重新生成该版本时，可以直接恢复当时的条件。&lt;/p&gt;
&lt;h2&gt;如何使用随机种子&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;打开恒盾C#混淆加密大师，选择需要处理的 DLL 或 EXE。&lt;/li&gt;
&lt;li&gt;根据项目需求，勾选代码保护、代码混淆和重命名等选项。&lt;/li&gt;
&lt;li&gt;在主界面下方找到“随机种子”输入框。&lt;/li&gt;
&lt;li&gt;输入便于识别的字母或数字，例如项目名称与版本号的组合。&lt;/li&gt;
&lt;li&gt;选择输出路径，点击“开始处理”。&lt;/li&gt;
&lt;li&gt;如果需要保留当前设置，点击“保存配置”。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;随机种子支持字母和数字。建议使用团队容易识别、能长期保存的内容，例如：&lt;/p&gt;
&lt;pre class=&quot;prism-highlight prism-language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;MyProduct150
Release202608
ClientA2026
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果不需要复现结果，保持输入框为空即可。&lt;/p&gt;
&lt;h2&gt;固定种子与留空随机应该怎么选&lt;/h2&gt;
&lt;p&gt;如果当前工作重点是测试、排错、回归或自动化构建，建议设置固定种子。这样多次处理的结果更容易比较，也便于其他开发者复现。&lt;/p&gt;
&lt;p&gt;如果重点是正式发布，并且希望不同批次的混淆结果保持差异，可以留空或者每个版本使用不同的种子。&lt;/p&gt;
&lt;p&gt;一个常见的策略是：测试阶段固定使用项目级种子，正式发布时按版本换用不同的种子。这样既方便日常验证，也能让不同版本之间保持足够的差异。&lt;/p&gt;
&lt;h2&gt;使用时需要注意什么&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;相同种子需要搭配相同的输入文件和配置，才能得到一致的结果。&lt;/li&gt;
&lt;li&gt;输入程序、保护选项或软件版本变化后，结果也可能跟着变。&lt;/li&gt;
&lt;li&gt;随机种子不是密码，不要在里面填写账号、密码等敏感信息。&lt;/li&gt;
&lt;li&gt;换随机种子不等于提高保护强度，实际效果取决于你启用的混淆和加密功能。&lt;/li&gt;
&lt;li&gt;需要复现正式版本时，记得同时保存输入文件、配置、版本号和种子。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;恒盾C#混淆加密大师的随机种子功能，让开发者可以根据实际需求决定混淆结果的稳定性。在排查问题、回归测试、团队协作和 CI/CD 场景中，固定种子可以大幅简化构建管理；而在需要不同版本保持差异的正式发布中，则可以留空或更换种子。合理使用这个配置项，可以让 C# 代码混淆的流程更加清晰、可控，也更适合长期的维护和自动化发布。&lt;/p&gt;
</description><pubDate>Mon, 03 Aug 2026 21:31:19 +0800</pubDate></item></channel></rss>