1. 目录结构:
(1)_imports.razor是一个全局using namespace的地方
(2)Platforms下的代码,虽然都放在同一个项目下,但是Platforms\Android下的.cs类,不能被其他地方访问,相当于是一个个独立的子项目


2. .razor 最终会被编译为一个类。
(1)可以为 xx.razor,添加一个文件 xx.razor.cs,里面定义public partial class xx

3. 也可以为 xx.razor,添加一个文件 xx.razor.css,里面设置html标签的样式,提供给xx.razor使用

4. Main.razor,其实就是 class Main了

5. 放在Shared中的.razor有如下特点:
(1). 是可以被【嵌入】到放在Pages的.razor中使用的。
(2). 在xxx.razor文件中,是没有@page "/xxx"这样的

6. 在Pages的.razor有如下特点:
(1) 在xxx.razor文件中,有标记@page "/xxx",等价于 :
[Route("/xxx")]
public partial class xx { }
(2) 使用@page "/",指定第一个弹出来的page
7. .razor中,html标签和c#属性关联起来,参考:https://www.cnblogs.com/jimsfriend/p/14017016.html

8. <NavLink>标签——用于页面跳转
(1) <NavLink>标签,相当于<a>标签,是跳转到某页面c。
(2) 跳转过程:
1. 点击<NavLink>,会“广播”路由消息,携带href参数;
2. Main.razor类会指定MainLayout.razor来处理;
3. MainLayout.razor,会在@body处,嵌入c页面
(3)每次页面跳转,.razor所生成的类,都会实例化一次;(重点)
9. 属性依赖注入,在.razor页面中,使用@inject NavigationManager nav,实例化的时候注入nav对象。在.razor.cs文件中,就可以直接使用nav这个对象了

10.NavigationManager nav,可以实现页面跳转,原理也是和 <NavLink>标签触发一样的

11. 使用bootstrap之外的图标:
(1)在“阿里巴巴”图标库中,将项目打包,下载解压,得到如下文件:
1. iconfont.js
2. iconfont.css
3. demo_index.html
(假设文件都放在css/open-iconic/font/alifonts/ 目录下)
(2)在css/index.html中,加入:
1. <link rel="stylesheet" href="css/open-iconic/font/alifonts/iconfont.css" />
2. <script src="css/open-iconic/font/alifonts/iconfont.js"></script>
(3)在要使用图标的时候,例如:
<span class="iconfont" aria-hidden="true"></span>
class 是 “iconfont”,其中的内容就是demo.html中的代码

12. 嵌入js:
<button type="button"
class="btn btn-primary" id="liveToastBtn"
onclick="@jstext">Show live toast</button>
@code{
const string jstext = "alert('hhhh');"; //这里就可以为所欲为了,直接写js给botton响应
}
13. 使用bootstrap
1. 需要下载bootstrap,里面包含各种 css, js文件
2. index.html中加入 <link rel="stylesheet" href="css/bootstrap/css/bootstrap.css" />
3. index.html中加入 <script src="css/bootstrap/js/bootstrap.js"></script>

14. 用户控件:
1. 用户控件,可以放在shared/UserControl.razor中,没有使用@page 路由
2. 在UserControl.razor中,可以声明,用于传递参数:
[Parameter]
public string Message { get; set; }
3. 在page.razor中,可以,xxx是传递的参数:
<UserControl Message="xxxx"></UserControl>

15. 需要自行创建 Resource\mipmap文件夹,将*.png放里面,才能在Android清单中选择图标

16. 需要自行创建Platforms\Android\Resources\drawable、mipmap-hdpi等等文件夹,并且将png全部拷贝进去

17. 需要设置Android应用程序图标,不要通过属性设置,仅仅设置MainActivity就可以, 例如 : mipmap/fmos2
[Activity(Theme = "@style/Maui.SplashTheme", Icon = "@mipmap/fmos2", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]

18. 针对不同平台实现不同的接口,例如Android要实现接口 IGetServiceNames,那么,应该:
1. 在Platforms/Android/Models下,新建类实现该接口
(不能像Xamarin该类的namespace上加上[assembly: Dependency(typeof(FmosMobile.Droid.Models.GetServiceNames))]) !!!!
2. 在MainApplication.cs中,的构造函数中,加入:
DependencyService.Register<IGetServiceNames, GetServiceNames>();
3. 使用的时候,就可以: var obj = DependencyService.Get<IExteralFileHelper>();

19. 关于数据双向绑定,查看:
1. https://learn.microsoft.com/zh-cn/aspnet/core/blazor/components/data-binding?view=aspnetcore-6.0
2. https://blog.csdn.net/sD7O95O/article/details/127399331
比较重要一点,务必要记住:
1. 绑定不像xaml,标签属性绑定关系要显式写出,而是根据“命名约定”,由框架编译的时候做绑定。
2. 以下 [Parameter],最好要成双出现,比如:T Property,一定要有对应的 “EventCallback<T> YearChanged”
假设这里是子控件 Shared\ChildBind.razor 的代码

<button @onclick="UpdateYearFromChild"> 点击触发UpdateYearFromChild() </button>

[Parameter]
public int Year { get; set; }

//这里是“命名约定”,必须要 Year + Changed,重点是,父page不需要对其显示赋值,由框架完成的。
//****重点,不成对出现会报错!!
[Parameter]
public EventCallback<int> YearChanged { get; set; }

void UpdateYearFromChild(){
Year = new Random().Next(1950, 2021);
await YearChanged.InvokeAsync(Year);
}

3. 父控件Parent.razor如何不通过显式对YearChanged赋值,达到收到ChildBind.Year值改变的通知:

<!--@bind-Year中的Year,是子控件的Year,year是Parent.year-->
<!--@bind-Year:event,其实可以不用写,因为根据“命名约定”规则,会默认是YearChanged。-->
<!--@bind-Year:event,意思应该是,由ChildBind哪个事件,触发Parent.year改变-->
<ChildBind @bind-Year="year"
@bind-Year:event="YearChanged"
/>
private int year{ get;set;}
4. 如果要在构造得时候填值,不用@,例如:<ChildBind Year="常量" />

20. 一般绑定:
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
//无需要自行调用javascript来更新<p>的内容,能自动更新
currentCount++;
}
}
21. 表单绑定:
<input @bind="InputValue" />
private string InputValue { get; set; }
这样绑定貌似只是单向的,字段改了不会通知表单,代码改了InputValue需要使用 this.StateHasChanged();通知UI

30. 标签事件:
不带参数: @onclick="UpdateYearFromChild"
带参数: @onclick="@(e => getSelectProject(i))"

31. page.razor通过@ref获取子组件引用:
<InnerMessageBox @ref="innerMessageBox"></InnerMessageBox>
InnerMessageBox innerMessageBox { get; set; }

32. 使用java的.jar包,需要:
1. 必须使用.net7 来创建项目
2. 创建Android绑定项目:
(1)并添加Jars文件夹,将.jar文件拷贝到里面;
(2)修改Android绑定库的配置文件:
在<Project>标签内,加入:
<ItemGroup>
<EmbeddedJar Include="Jars\RuideApi.jar" />
</ItemGroup>
3. MAUI的项目,要想引入Android绑定项目,只能将项目修改为只支持安卓的:
(1)<!--<TargetFrameworks>net7.0-android;net7.0-ios;net7.0-maccatalyst</TargetFrameworks>--> 改为:
<TargetFrameworks>net7.0-android</TargetFrameworks>
(2) 注释掉:
<!--<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net7.0-windows10.0.19041.0</TargetFrameworks>-->
<!-- <TargetFrameworks>$(TargetFrameworks);net7.0-tizen</TargetFrameworks> -->

33. 如果编译时报 PE image does not have metadata,就是有一个包有问题,可能是引用了本地的dll导致的,要找出来干掉,改用nuget的

34. 要使用javascript动态移除【列表】【表格】元素的,要设置 protected override bool ShouldRender(){ return false ;} ,否则会出错

35. 替换启动画面 :https://learn.microsoft.com/zh-cn/dotnet/maui/user-interface/images/splashscreen?tabs=android
同时也改项目文件

36. 关于X3dom
1. X3dom默认Y轴向上, X轴向屏幕右方,Z轴向屏幕外边
2. 具体教程:http://x3dgraphics.com/examples/X3dForWebAuthors/
3. css文件,也必须弄到razor.css中,不能单独在index.html中引入

37. 如果使用<select class="form-select"></>标签,那么弹出选择窗口后,依然会触发一次OnAfterRender
弹出输入法,也会触发!!!!!!!!!!!!1

OnAfterRender(bool firstRender); //使用 NavigationManager.NavigateTo导航到其他页面,也是会触发的!!

38. 关于返回键
1. 如果弹出模态框,使用返回键(不加限制)会导致页面后退,或者模态框消失但是页面不能操作。
2. 常规方法在mainactivity监控是无效的在Blazor项目中无效,因为webview会优先接管返回按钮的事件,并阻止向上传播到 MainActivity中,需要重写
public override bool DispatchKeyEvent(KeyEvent e)
{
if (e.KeyCode == Keycode.Back)
if (e.Action == KeyEventActions.Down)
}
参考:https://www.cnblogs.com/sunday866/p/17331304.html
使用返回键关闭模态框
var bc = DependencyService.Get<IBackKeyBroadcaster>();
bc.OnBackKeyPress = () =>
{
this.isVisable = false;
bc.OnBackKeyPress = null;
JS.InvokeVoidAsync(CssConst.CloseDialog, "bubledialog");
return true;
};

39. 工作负载:
error NETSDK1147: 要构建此项目,必须安装以下工作负载: wasm-tools
error NETSDK1147: 要安装这些工作负载,请运行以下命令: dotnet workload restore
打开CMD,运行:
dotnet workload install maui
dotnet workload install maui-android
dotnet workload install android
重启vs

39. 错误排查:
1. MAUI [chromium] [INFO:CONSOLE(1)] "Failed to compare two elements in the array. [chromium] at System.Collections.Generic.ArraySortHelper`1[[Microsoft.AspNetCore.Components.Routing.RouteEntry, Microsoft.AspNetCore.Components, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].Sort(Span`1 keys, IComparer`1 comparer)
解决办法:1. 肯定是有@page "/SingleStMs/SingleStTaskPage" 类似的重复

40. 权限设置
1. 必须在AndroidManifest.xml中声明需要哪些权限。
2. 必须使用代码检查权限,如下:
async Task CheckPermission<T>() where T : BasePermission, new()
{
PermissionStatus status = await Permissions.CheckStatusAsync<T>();
if (status != PermissionStatus.Granted)
{
await Permissions.RequestAsync<T>();
}
}
调用:await CheckPermission<Permissions.NetworkState>();
3. 如果是蓝牙,还需要自定义权限:
/// <summary>
/// 资料 https://segmentfault.com/a/1190000042518175
/// </summary>
public class BluetoothPermissions : Permissions.BasePlatformPermission
{
public override (string androidPermission, bool isRuntime)[] RequiredPermissions =>
new List<(string androidPermission, bool isRuntime)>
{
(global::Android.Manifest.Permission.AccessFineLocation, true),
(global::Android.Manifest.Permission.AccessCoarseLocation, true),
(global::Android.Manifest.Permission.Bluetooth, true),
(global::Android.Manifest.Permission.BluetoothAdmin, true),
}.ToArray();
}
调用:await CheckPermission<BluetoothPermissions>();

adb指令:
https://blog.csdn.net/m0_57098592/article/details/129441707
日志输出: adb logcat -d | findstr com.southgz.FmosMobile.MAUI > C:\Users\pyl\Desktop\appError.txt
查看:
https://learn.microsoft.com/zh-cn/xamarin/android/deploy-test/debugging/android-debug-log?tabs=windows

无线调试
adb tcpip 5555
adb connect 192.168.1.111

adb shell ip -f inet addr 查看已连接wifi的设备的Ip

要想用JavaScript中设置元素中文,要先转为Unicode
https://www.bejson.com/convert/unicode_chinese/
比如:“操作” 的Unicode 为 \u64cd\u4f5c,那么:
<div>\u64cd\u4f5c</div>

41.[推荐] 使用命令行发布,可以得到签名的.apk:参考:https://www.zhihu.com/tardis/zm/art/576654157?source_id=1005

1. 最好要决定使用命令行,就一开始就使用。连 .keystore文件也使用命令行创建
在.csproj下,CMD:
keytool -genkey -v -keystore myapp.keystore -alias key -keyalg RSA -keysize 2048 -validity 10000
按照提示就可以创建了
正常的话,会生成:
myapp.keystore,在项目文件夹下

2. 在.csproj文件所在位置,CMD,运行:

项目文件加入,事先加上这个,声明使用哪个keystore
<PropertyGroup Condition="$(TargetFramework.Contains('-android')) and '$(Configuration)' == 'Release'">
<AndroidKeyStore>True</AndroidKeyStore>
<!--设置为 True 对应用进行签名-->
<AndroidSigningKeyStore>myapp.keystore</AndroidSigningKeyStore>
<!--在上一部分中创建的密钥存储文件:myapp.keystore-->
<AndroidSigningKeyAlias>key</AndroidSigningKeyAlias>
<!--传递给 keytool 工具的参数值:键-->
<AndroidSigningKeyPass>southgz123</AndroidSigningKeyPass>
<!--创建密钥存储文件时提供的密码-->
<AndroidSigningStorePass>southgz123</AndroidSigningStorePass>
<!--创建密钥存储文件时提供的密码-->
</PropertyGroup>

在.csproj文件夹下,CMD
3. dotnet publish -f:net7.0-android -c:Release /p:AndroidSigningKeyPass=southgz123 /p:AndroidSigningStorePass=southgz123 /p:AndroidSdkDirectory=C:\Android\android-sdk
4. 遇到错误:
1. Xamarin Forms error MSB6006: “java.exe”已退出,代码为 2 解决办法,参见:https://www.cnblogs.com/mschen/p/9525209.html
在“项目-属性 - Android - 勾选Multi-Dex”
2. [注意] 调试的时候,需要还原:不要勾选R8优化、不要勾快速部署。

42. error NETSDK1181: 获取包版本时出错: 包“Microsoft.Android.Ref.33”在工作负载清单中不存在。
修改<TargetFrameworks>net8.0-android34.0</TargetFrameworks>

error XA1036: AndroidManifest.xml //uses-sdk/@android:minSdkVersion '28' does not match the $(SupportedOSPlatformVersion) value '24.0' in the project file (if there is no $(SupportedOSPlatformVersion) value in the project file, then a default value has been assumed).

在AndroidManifest.xml,改为<uses-sdk android:minSdkVersion="29" android:targetSdkVersion="34" />

43. Java.Lang.SecurityException: 'com.southgz.FmosMobile.MAUI: One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts'
//注册广播时,必须包含“(ActivityFlags)2”
RegisterReceiver(fmosBroadcastReceiver, new IntentFilter(FmosBroadcastReceiver.Action), (ActivityFlags)2);

45. 如果不允许再公共目录的download目录下存储,需要:
只要在AndroidManifest.xml中的application标签中添加
android:requestLegacyExternalStorage="true"

46. 发布出现“ android存档无效 不是.apk文件 ”, 要重新生成项目再试

47. 发布出现“无法存档文件,因为打包进程失败”,需要将项目设为“release”
使用快速部署,不勾
每个ABI生成,不勾
使用增量打包,勾
多dex,不勾
R8代码收缩器,不勾
AOT,Debug不勾,Release勾
LLVM,不勾
启动跟踪,Debug不勾,Release勾
垃圾回收,勾
跟踪修整,Debug不勾,Release勾
重启VS

49. //必须使用注入才行
//var JS = DependencyService.Get<IJSRuntime>(); 这样子拿不到JS实例
[Inject]
public IJSRuntime JS { get; set; } //这样子才可以

50. java.lang.unsatisfiedlinkerror: dlopen failed: library "libmonosgen-2.0.so" not found
修复方法是取消选中 .csproj 文件属性窗口的 Android 选项部分中的“使用共享运行时”。
<EmbedAssembliesIntoApk>False</EmbedAssembliesIntoApk>

51. maui didn't find class "mainapplication" on path: dexpathlist
不要听微软,在MainApplication后面,using加任何标签!!!

50条MAUI踩坑记的更多相关文章

  1. Spark踩坑记——Spark Streaming+Kafka

    [TOC] 前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark strea ...

  2. Spark踩坑记——数据库(Hbase+Mysql)

    [TOC] 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streami ...

  3. Spark踩坑记——从RDD看集群调度

    [TOC] 前言 在Spark的使用中,性能的调优配置过程中,查阅了很多资料,之前自己总结过两篇小博文Spark踩坑记--初试和Spark踩坑记--数据库(Hbase+Mysql),第一篇概况的归纳了 ...

  4. EOS踩坑记

    [EOS踩坑记] 1.每个account只能更新自己的contract,即使两个account的秘钥相同,也不允许. 如下,使用alice的权限来更新james的contract.会返回 Missin ...

  5. 记一次 Spring 事务配置踩坑记

    记一次 Spring 事务配置踩坑记 问题描述:(SpringBoot + MyBatisPlus) 业务逻辑伪代码如下.理论上,插入数据 t1 后,xxService.getXxx() 方法的查询条 ...

  6. [转]Spark 踩坑记:数据库(Hbase+Mysql)

    https://cloud.tencent.com/developer/article/1004820 Spark 踩坑记:数据库(Hbase+Mysql) 前言 在使用Spark Streaming ...

  7. Spark踩坑记——数据库(Hbase+Mysql)转

    转自:http://www.cnblogs.com/xlturing/p/spark.html 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库 ...

  8. Spark踩坑记:Spark Streaming+kafka应用及调优

    前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark streaming从k ...

  9. Vue + TypeScript + Element 搭建简洁时尚的博客网站及踩坑记

    前言 本文讲解如何在 Vue 项目中使用 TypeScript 来搭建并开发项目,并在此过程中踩过的坑 . TypeScript 具有类型系统,且是 JavaScript 的超集,TypeScript ...

  10. WinUI 3 踩坑记:从创建项目到发布

    本文是 WinUI 3 踩坑记 的一部分,该系列发布于 GitHub@Scighost/WinUI3Keng,若内容出现冲突以 GitHub 上的为准. 创建项目 现在 WinUI 3 的入门体验比刚 ...

随机推荐

  1. JS遍历树形数据

    树形数据结构遍历某个key值 深度优先遍历(DFS) let tree = [{ id: '1', name: '节点1', children: [{ id: '1-1', name: '节点1-1' ...

  2. [2] HEVD 学习笔记:栈溢出漏洞训练

    2. HEVD 栈溢出漏洞训练 2.1 漏洞原理 ​ 当函数退出的时候,会将保存在栈中的返回地址取出,跳转到该地址继续执行,以此来执行函数调用以后的程序.而如果用户的输入没有得到控制,覆盖掉了这个返回 ...

  3. 强化学习从基础到进阶-常见问题和面试必知必答[8]:近端策略优化(proximal policy optimization,PPO)算法

    强化学习从基础到进阶-常见问题和面试必知必答[8]:近端策略优化(proximal policy optimization,PPO)算法 1.核心词汇 同策略(on-policy):要学习的智能体和与 ...

  4. 总结一个问题:csdn发布文章页面为空或者创作内容管理为空

    总结一个问题:csdn发布文章页面或者创作内容管理为空 解决方案: 打开chrome浏览器的设置: 点击清除数据: 选择高级里清除数据,一般24小时就可以了,不行就7天

  5. 【八】强化学习之DDPG---PaddlePaddlle【PARL】框架{飞桨}

    相关文章: [一]飞桨paddle[GPU.CPU]安装以及环境配置+python入门教学 [二]-Parl基础命令 [三]-Notebook.&pdb.ipdb 调试 [四]-强化学习入门简 ...

  6. blazor maui hybrid app显示本地图片

    啊... ... 一通操作下来感觉就是两个字 折磨 跨平台有跨平台的好处 但框架本身支持的有限 很多东西做起来很曲折 哎 这里总结一下笔者为了折腾本地图片显示的尝试 为什么要做本地图片展示呢 如果是做 ...

  7. Android Graphics 显示系统 - 如何模拟多(物理)显示屏?

    " 本着花小钱办大事,不花钱也办事的原则,为了避免花钱买设备,那如何更便捷地学习/测试Android多屏显示的内容呢?本文就给大家介绍一种模拟Android多个物理屏幕显示的方法." ...

  8. sanic和tornado的简单性能测试

    操作系统 : CentOS7.3.1611_x64 Python 版本 : 3.6.8 tornado版本:6.0.2 sanic版本:19.9.0 CPU : Intel(R) Core(TM) i ...

  9. 使用lvs实现ftp的负载均衡

    操作系统:CentOS6.5_x64 问题描述 使用lvs实现ftp的负载均衡 为了使模型足够简单,这里只实现了loadblance,HA并未实现,可以借助keepalived实现. 具体实现 hos ...

  10. C# 二十年语法变迁之 C# 2,C# 3 ,C# 4参考

    C# 二十年语法变迁之 C# 2,C# 3 ,C# 4参考 https://benbowen.blog/post/two_decades_of_csharp_i/ 自从 C# 于 2000 年推出以来 ...