Xamarin.Android开发中遇到的问题
<p>安卓版本和SDK</p><p><img src="https://img2020.cnblogs.com/blog/727485/202110/727485-20211017105835295-1962414906.png" alt="" loading="lazy"></p>
<h2>开发</h2>
<h3><span style="font-size: 1.17em">1、Resource.Id未包含xxx的定义</span></h3>
<p>打开了一个OK的Id,是位于\obj\Debug\90\designtime\Resource.designer.cs ,打开文件搜索xxx,果然没有。</p>
<p>删除此文件 重新生成项目,并没有重新生成Resource.designer.cs </p>
<p>解决方法:</p>
<p>删除整个obj文件夹,重新生成项目;</p>
<p><span style="color: rgba(255, 0, 0, 1)">或者重启VS</span>,自动重新生成Resource.designer.cs了,并且含有xxx</p>
<h3 class="title-article">2、Button文本默认大写</h3>
<p>参考:xamarin forms中的Button文本默认大写</p>
<p>将按钮的属性textAllCaps都改为false。默认没有设置 是true。</p>
<h3>3、ADB0020: Android ABI 不匹配。</h3>
<p>问题1:你正将应用支持的“armeabi,armeabi-v7a,x86”ABI 部署到 ABI“x86_64”的不兼容设备。应创建匹配其中一个应用 ABI 的仿真程序,或将“x86_64”添加到应用生成的 ABI 列表中</p>
<p>问题原因:应该是选择的模拟器(X86_64)不匹配,需要创建一个“armeabi,armeabi-v7a,x86”是模拟器来调试。</p>
<p>或者看下“使用共享运行时”是否选中</p>
<p><img src="https://img2020.cnblogs.com/blog/727485/202003/727485-20200331133240331-1506194991.png" alt=""></p>
<p>参考:</p>
<p>说说Android项目中的armeabi,armeabi-v7a和x86</p>
<p>Android 关于arm64-v8a、armeabi-v7a、armeabi、x86下的so文件兼容问题</p>
<p>问题2:Please open the Android SDK Manager and install the latest version of 'Android Support Repository' from the 'Extras' section, and then reload your solution.</p>
<p>问题原因:上一步选择X86处理器后,需要安装相应的SDK,和工具中的Android Support Repository</p>
<p><img src="https://img2018.cnblogs.com/blog/727485/201909/727485-20190926142453039-454139862.png" alt=""></p>
<p><img src="https://img2018.cnblogs.com/blog/727485/201909/727485-20190926150422547-172457369.png" alt=""></p>
<h3>4、方法过时</h3>
<p><strong>4.1 </strong></p>
<p>在使用PageRenderer时提示这个构造函数已经过时,发生这种情况的原因是从v2.5版本开始的Xamarin.Forms非常简单,<span style="color: rgba(255, 0, 0, 1)">将Xamarin.Forms.Forms的Context属性标记为过时</span>。 因此,要获取渲染器的全局上下文,有必要<span style="color: rgba(255, 0, 0, 1)">调用该渲染器的基类</span>,这意味着在构造函数中,您需要执行以下操作: 添加以下代码即可(Please use PageRenderer(Context) instead.)</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> WriteEmailPageRenderer(Context context) : <span style="color: rgba(0, 0, 255, 1)">base</span><span style="color: rgba(0, 0, 0, 1)">(context)
{
}</span></pre>
</div>
<p>参考:How do I resolve WebViewRenderer is obsolete</p>
<p><strong>4.2 Context is obsolete as of version 2.5. Please use a local context instead</strong></p>
<p>报过时的写法:Android.Content.Context content = Forms.Context; 或者 Activity activity = (Activity)Forms.Context;</p>
<p>在Dependencies中定义特定平台的功能时,使用Forms.Context会提示已过时,请改为使用本地环境。</p>
<p><span style="color: rgba(255, 0, 0, 1)">解决方案是在不引用Xamarin.Forms.Forms.Context的情况下获取本地上下文</span>。</p>
<p><span style="color: rgba(255, 0, 0, 1)">注:Android.Content.Context是应用程序环境全局信息上下文,Activity都是继承自此类。</span></p>
<p>有两种方式解决:</p>
<p>方式1、在接口中提供Init(),然后在MainActivity中调用:VersionHelper.Init(this);</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> VersionHelper : IVersionHelper
{
</span><span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> Context _context;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> Init(Context context)
{
_context </span>=<span style="color: rgba(0, 0, 0, 1)"> context;
}
...</span></pre>
</div>
<p>方式2、在MainActivity类中创建一个静态属性,并将其设置为MainActivity实例:</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt="" id="code_img_closed_42d0ba6e-6e48-489a-8316-6f34d1452eca" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="" id="code_img_opened_42d0ba6e-6e48-489a-8316-6f34d1452eca" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_42d0ba6e-6e48-489a-8316-6f34d1452eca" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span> MainActivity : <span style="color: rgba(0, 0, 255, 1)">global</span><span style="color: rgba(0, 0, 0, 1)">::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
</span><span style="color: rgba(0, 0, 255, 1)">internal</span> <span style="color: rgba(0, 0, 255, 1)">static</span> MainActivity Instance { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
</span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">override</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> OnCreate(Bundle bundle)
{
...
</span><span style="color: rgba(0, 0, 255, 1)">global</span>::Xamarin.Forms.Forms.Init(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">, bundle);
Instance </span>= <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">;
Xamarin.Forms.DependencyService.Register</span><IVersionHelper, VersionHelper><span style="color: rgba(0, 0, 0, 1)">();
LoadApplication(</span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> App());
}
}</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>然后接口中使用</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt="" id="code_img_closed_8777fbc3-6b14-4aa6-b048-9dc61464c299" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="" id="code_img_opened_8777fbc3-6b14-4aa6-b048-9dc61464c299" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_8777fbc3-6b14-4aa6-b048-9dc61464c299" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Android.Content;
</span><span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> DependencyServiceAndLocalContext.Droid
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> VersionHelper : IVersionHelper
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> GetVersionNumber()
{
</span><span style="color: rgba(0, 0, 255, 1)">var</span> versionNumber = <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">.Empty;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (MainActivity.Instance != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
{
versionNumber </span>=<span style="color: rgba(0, 0, 0, 1)"> MainActivity.Instance.PackageManager.GetPackageInfo(
MainActivity.Instance.PackageName, </span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">).VersionName;
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> versionNumber;
}
}
}</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>参考:Xamarin.Forms 2.5 and Local Context on Android</p>
<h3>5、权限问题</h3>
<p>需要获取设备权限时,是由设备自动弹出提醒的。</p>
<p>读权限和写权限由区别:</p>
<ul>
<li>写:WRITE_EXTERNAL_STORAGE 则其具有写和读权限;</li>
<li>读:READ_EXTERNAL_STORAGE 则其只具有读权限</li>
</ul>
<p> </p>
<p><strong>5.1 写文件 、文件目录</strong></p>
<p>最近在app中做一个 录音功能时,需要将录音文件保存在手机上,一开始使用了:Android.OS.Environment.ExternalStorageDirectory.AbsolutePath 获取目录(/storage/emulated/0/),但是这样写入文件需要获取设备的写权限,有点不太友好。</p>
<p>在参考了:</p>
<p>Android私有目录和公有目录</p>
<p>open failed: EACCES (Permission denied)解决方法 AndroidQ</p>
<p><img src="https://img2020.cnblogs.com/blog/727485/202105/727485-20210512171005946-999946683.png" alt="" loading="lazy"></p>
<p> </p>
<p> 之后。</p>
<p><span style="color: rgba(255, 0, 0, 1)">在存储一些临时文件时,可以选用Context.GetExternalFilesDir("").AbsolutePath 方法,不需要获取设备的写权限;</span></p>
<p><span style="color: rgba(255, 0, 0, 1)">获取到目录为:/storage/emulated/0/Android/data/com.app名称/files/</span></p>
<p>其中:<strong> /storage/emulated/0/目录,就是华为手机打开的 内部存储的根目录</strong>。</p>
<p> </p>
<h2>调试</h2>
<h3>1、Xamarin.android不能显示网络、远程图片 </h3>
<p>调试时从IDE的输出可以看出原因:Image load failed: System.ObjectDisposedException: Can not access a closed Stream. 不知这个问题是不是还没有去修复,还是不准备修复</p>
<p>因为看到Mircsoft官方示例eshop都是用的一个开源包:https://github.com/luberda-molinet/FFImageLoading </p>
<p><span style="background-color: rgba(255, 255, 0, 1)">注意:各个平台需要调用: CachedImageRenderer.Init(false); </span> 【上述github有使用方法】</p>
<p>否则 会报错:</p>
<p> "Please call CachedImageRenderer.Init method in a platform specific project to use FFImageLoading!"</p>
<h3>2、Can't install because provider name com.xxx.fileprovider (in package yyy) is already used by com.mesince]</h3>
<div>
<div>
<p>这个问题其实本质就是手机里已经安装有同名的<code>Provider</code>的APK了.</p>
<p>比如我在<strong>甲APP</strong>(<code>com.xxx</code>)中的<code>AndroidManifest.xml</code>中定义了一个Provider,<br>
安装完这个<strong>甲APP</strong>,<br>
我把代码里的<code>ApplicationId</code>改成<code>com.yyy</code>,即换皮成乙APP(<code>com.yyy</code>) ,<br>
此时如果没有把<code>Provider</code>的<code>android:authorities</code>的属性也换掉,<br>
安装<strong>乙APP</strong>到手机上,provider就会和甲APP的冲突.</p>
</div>
需要修改项目中的配置文件:AndroidManifest.xml,可以改为如下</div>
<div>
<pre class="line-numberslanguage-bash"><code class="language-bash">android:authorities= ${applicationId}.provider</code></pre>
</div>
<p> </p>
<p>参考: 该文件包与具有同一名称的现有文件包存在冲突</p>
<p> </p>
<h3>3、Android http 不能联网:Cleartext HTTP traffic to not permitted</h3>
<p>在尝试 请求外部的WebApi时,报出错误。</p>
<p>解决:在AndroidManifest.xml配置文件的<application>标签中插入:<code class="hljs java"> </code></p>
<p><code class="hljs java">android:usesCleartextTraffic=<span class="hljs-string">"true"</span></code></p>
<h3>4、Android模拟机时间修改</h3>
<p>没做任何修改的前提下,其时间是美国纽约的时区,相对中国是-8小时的。所以程序中DateTime.Now获取的比中国时间小8小时</p>
<p>可以自己修改为和中国一样。 </p>
<p><img src="https://img2018.cnblogs.com/i-beta/727485/202002/727485-20200220211056265-558954082.png" alt=""></p>
<p> </p>
<p>本来想设置 图中1处的时区,但是发现没有中国的。于是直接改图中2处的时间。</p>
<p>参考:安卓模拟器怎么设置时间日期</p>
<h3>5、listView.ScrollTo不生效</h3>
<p>需要看下滚动的代码是否有UI线程执行的</p>
<div class="cnblogs_code">
<pre>txtMessage.Focused +=<span style="color: rgba(0, 0, 0, 1)"> TxtMessage_Focused;
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span> TxtMessage_Focused(<span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)"> sender, FocusEventArgs e)
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (listChatMessage.Count > <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
{
Task.Delay(</span><span style="color: rgba(128, 0, 128, 1)">100</span>).ContinueWith((t) =><span style="color: rgba(0, 0, 0, 1)">
{
Device.BeginInvokeOnMainThread(() </span>=><span style="color: rgba(0, 0, 0, 1)">
{
listView.ScrollTo(listChatMessage.Last(), ScrollToPosition.End, </span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">);
});
});
}
}</span></pre>
</div>
<p>参考:xamarin优化listView.ScrollTo</p>
<h3>6、not attached to window manager</h3>
<p>not attached to window manager有许多场景发生。最近在做设备锁时,弹出进度圈和取消时碰到此问题</p>
<p>调试判断出大概是Activity 已经销毁了,再调Dismiss时失败,,【泄露】</p>
<p>最终修改代码,发现确实是开启的dialog在Activity销毁之前,没有关闭。。然后在Activity销毁了再去dismiss。</p>
<h3>7、Unable to add window -- token android.os.BinderProxy@b1bab0a is not valid; is your activity running?</h3>
<p>最近在做设备锁时,需要弹窗的地方碰到此问题</p>
<p>问题:Activity不是处于运行状态</p>
<p>调试查看报错处的Activity是哪个,代码中写的是Activity context = (Activity)Forms.Context;</p>
<p>System.Console.WriteLine(TAG + context.LocalClassName);<br>发现此Activity调用了OnDestroy()马上就销毁了,所以他不是在运行中。。</p>
<p>修改Activity的赋值:Activity activity = MainActivity.Instance; </p>
<h3>8、net::ERR_CLEARTEXT_NOT_PERMITTED</h3>
<p>在安卓9.0中调试WebView加载网页时错误。</p>
<p>解决方法: 在AndroidManifest文件中的节点Application中加入 android:usesCleartextTraffic=<span class="hljs-string"><span class="hljs-string">"true"</span></span></p>
<h3>9、Xamarin.forms包加入不进</h3>
<p>在迁移一个项目后,Xamarin.Android中本来有Xamarin.Forms这个包的,但是同事从远程拉取代码后,没有显示此包,导致调试不通过。</p>
<p>报错(17个错误):style attribute 'attr/colorPrimaryDark (aka com.mesince:attr/colorPrimaryDar</p>
<p><img src="https://img2020.cnblogs.com/blog/727485/202005/727485-20200508093014057-1036472720.png" alt=""></p>
<p> </p>
<p> 在Nuget中引入了 但还是不行。后来尝试 从解决方案中卸载此Xamarin.Android项目,重新添加,居然可以显示了,好奇怪的问题!</p>
<h3>10、调试不进断点</h3>
<p>这种一般是vs配置或者项目属性配置的问题,</p>
<p>有几个思路:</p>
<p>1) 是否是Debug模式</p>
<p>2)清理解决方案重新调试</p>
<p>3)项目属性,共享运行时 得勾选</p>
<p><img src="https://img2020.cnblogs.com/blog/727485/202009/727485-20200904152030842-1705813722.png" alt="" loading="lazy"></p>
<p> </p>
<h3>11、项目生成报错:Xamarin.Forms targets have been imported multiple times. Please check your project file and remove the duplicate import(s)</h3>
<p>见问题12</p>
<h3>12、您的项目未引用“.NETPortable,Version=v4.5,Profile=Profile111”框架。在项目文件的“TargetFrameworks”属性中添加对“.NETPortable,Version=v4.5,Profile=Profile111”的引用,然后重新运行NuGet restore。</h3>
<p>以上两个问题都可以参考</p>
<p>参考:Error XF001: Xamarin.Forms targets have been imported multiple times</p>
<p>这可能是因为对NuGet包使用PackageReference</p>
<p>This can be because of the move to using PackageReference for your NuGet packages and a simple fix awaits you.</p>
<ol>
<li>Close Visual Studio and navigate to the Solution in File Explorer</li>
<li>Delete the hidden .vs folder</li>
<li>Go into each affected project sub folder and delete the following files; project_name.nuget.props and project_name.nuget.targets</li>
<li>Open the solution in Visual Studio, do a Clean and Rebuild, </li>
</ol>
<p>意思是:关闭vs,进到解决方案目录,删除影藏文件夹: .vs ;进到各个项目目录,删除.obj文件夹 【里面含有 project_name.nuget.props and project_name.nuget.targets】。</p>
<h3>13、attribute android:requestLegacyExternalStorage not found.</h3>
<p>compileSdkVersion 版本设置为29或以上 (android 10+)</p>
<p> Android 中如何选择 compileSdkVersion, minSdkVersion 和 targetSdkVersion<br><br></p>
<h3>14、存档不成功</h3>
<p>存档发布成apk文件时报错,</p>
<p><img src="https://img2020.cnblogs.com/blog/727485/202105/727485-20210511194237348-1619254223.png" alt="" loading="lazy"></p>
<p> </p>
<p> 需要禁用”使用共享的Mono运行时“,在属性->Android选项中,禁用。若此处没有,则可以打开项目文件(.csproj)本身去修改:</p>
<p><AndroidUseSharedRuntime>false</AndroidUseSharedRuntime></p>
<p> </p><br><br>
来源:https://www.cnblogs.com/peterYong/p/11534341.html
頁:
[1]