Заметки |
Заметки |

введение

Чтение и запись файлов

ссылка:

Внешнее чтение и запись

Приложения могут сохранять файлы двух разных типов на внешнем хранилище:

  • преданный документ – Преданный документ специфичен для приложенияиздокумента (но по-прежнему глобально доступен для чтения и глобальной записи). Android ожидатьпреданныйдокументхранилищесуществовать外部хранилищеначальствоизидентификация Оглавлениесередина。 Несмотря на то, что этот документ называется «преданный», он по-прежнему доступен и может использоваться другими приложениями на вашем устройстве, Android. Никакой особой защиты им не предоставляется.
Язык кода:javascript
копировать
// преданный外部хранилище Оглавление
// /storage/emulated/0/Android/data/com.companyname.app/files/
Android.Content.Context.GetExternalFilesDir(string type)
  • общественный документ – Эти документы не предназначены для конкретного приложения и могут свободно распространяться.
Язык кода:javascript
копировать
// Основное внешнее хранилище
// /storage/emulated/0/
Android.OS.Environment.ExternalStorageDirectory

Android Считайте внешнее хранилище опасными разрешениями, которые обычно требуют от пользователя предоставления разрешения на доступ к ресурсу. Пользователи могут отозвать это разрешение в любое время. Это означает, что запрос разрешения во время выполнения должен выполняться перед любым доступом к файлу. Приложениям автоматически предоставляется разрешение на чтение и запись своих личных файлов. существоватьпользовательРазрешение полученоИзназад,Приложения могут читать и записывать файлы, принадлежащие другим приложениям.

Язык кода:javascript
копировать
//global::Android.OS.Environment.ExternalStorageDirectory.AbsolutePath :Установить Android из root Оглавление
//Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)::Получить данные AndroidОглавление
var path = global::Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);

// создаватьдокумент
System.IO.Directory.CreateDirectory(path);

Разрешения на внешнее хранилище

Все приложения Android должны объявить одно из двух разрешений для внешнего хранилища в AndroidManifest.xml.

Чтобы определить разрешения, необходимо указать следующие два: uses-permission Один из элементов, добавленных в AndroidManifest.xml:

Язык кода:javascript
копировать
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Примечание. Ниже есть ошибка.

Как указано выше, в файле свойств проекта Android имеется файл AndroidManifest.xml. существовать

Язык кода:javascript
копировать
<application android:label="cardionNet2.Android"></application> 

Симога

Этот визуальный осмотр неправильный, просто добавьте его прямо, не надо сюда ставить;

Язык кода:javascript
копировать
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.demoapp" android:installLocation="auto">
	<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
	<application android:label="DemoApp.Android" android:theme="@style/MainTheme"></application>
	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
</manifest>

Первый шаг перед записью на внешнее хранилище — проверить, доступно ли оно для чтения или записи. Android.OS.Environment.ExternalStorageState Свойство содержит строку, определяющую состояние внешнего хранилища. Это свойство возвращает строку, представляющую статус.

Язык кода:javascript
копировать
bool isReadonly = Environment.MediaMountedReadOnly.Equals(Environment.ExternalStorageState);
bool isWriteable = Environment.MediaMounted.Equals(Environment.ExternalStorageState);

полностью квалифицированный

Язык кода:javascript
копировать
bool isReadonly = Android.OS.Environment.MediaMountedReadOnly.Equals(Android.OS.Environment.ExternalStorageState);
            bool isWriteable = Android.OS.Environment.MediaMounted.Equals(Android.OS.Environment.ExternalStorageState);

Жизненный цикл приложения

ссылка:

Application Базовый класс предоставляет следующую функциональность:

методы жизненного цикла Application Класс содержит три виртуальных метода, которые можно переопределить в ответ на изменения жизненного цикла:

  • OnStart - существоватьзапускатьприложениечасвызовэто。
  • OnSleep - Каждыйкогдаприложениеперевод вназадбашнячасвызовэто。
  • OnResume - приложениеотправить вназадбашняназадвосстанавливатьсячасвызов。

макет

ссылка:

JarBinding Bugly

Xamarin.Forms Shell

ссылка:

визуальная иерархия

Shell -> FlyoutItem / TabBar -> Tab -> ShellContent -> ContentPage FloutItem: всплывающее окно TabBar: нижняя вкладкастолбец Tab: Содержимое группы когда Tab Есть несколько ShellContent,час,Будут снова распределены внутри компании, нравиться Tab родитель TabBar,Затем отобразится страница существования. Верхние вкладки навигации, соответствующие нескольким ShellContent, нравиться Tab родитель FlyoutItem,волясуществоватьпереписываться Отображение нескольких подпанелей под панелью (ShellContent) нравитьсясуществовать FloutItem / TabBar Пишите прямо в ShellContent,воля Воля Каждый个ShellContent Неявно завернутый в Tab середина

Пополнить: и TabBar класс это ShellItem псевдоним для класса, в то время как Tab класс это ShellSection Псевдоним для класса. Поэтому также возможно Shell -> FlyoutItem / ShellItem -> ShellSection -> ShellContent -> ContentPage Поэтому для FlyoutItem Объекты должны быть переопределены при создании пользовательских средств визуализации. CreateShellItemRenderer метод, для Tab Объекты должны быть переопределены при создании пользовательских средств визуализации. CreateShellSectionRenderer метод.

Язык кода:javascript
копировать
<!-- When the Flyout is visible this will be a menu item you can tie a click behavior to  -->
<MenuItem Text="Logout" StyleClass="MenuItemLayoutStyle" Clicked="OnMenuItemClicked">
</MenuItem>

Кнопка выхода из системы появляется сбоку

когда сторона (Flyout) всплывающее окно час,MenItem будет отображаться

MenuItem: всплывающее окноиз пункта меню

всплывающее окно

ссылка:

Доступ к нему можно получить с помощью значка или проведя пальцем по краю экрана. всплывающее окно по необязательному заголовку, врагее Элемент окна, дополнительный пункт меню и дополнительный нижний колонтитул состоит из:

Язык кода:javascript
копировать
<!-- 
	When the Flyout is visible this defines the content to display in the flyout.
	FlyoutDisplayOptions="AsMultipleItems" will create a separate flyout item for each child element    
	https://docs.microsoft.com/dotnet/api/xamarin.forms.shellgroupitem.flyoutdisplayoptions?view=xamarin-forms
-->
<FlyoutItem Title="первая страница" Icon="icon_about.png">
    <ShellContent Route="HomePage" ContentTemplate="{DataTemplate local:HomePage}" />
</FlyoutItem>
<FlyoutItem Название="Список" Icon="icon_feed.png">
    <ShellContent Route="ItemsPage" ContentTemplate="{DataTemplate local:ItemsPage}" />
</FlyoutItem>
<FlyoutItem Title="настраивать" Icon="icon_setting.png">
    <ShellContent Route="SettingPage" ContentTemplate="{DataTemplate local:SettingPage}" />
</FlyoutItem>

неявное преобразование

Язык кода:javascript
копировать
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:controls="clr-namespace:Xaminals.Controls"
       xmlns:views="clr-namespace:Xaminals.Views"
       x:Class="Xaminals.AppShell">
    <FlyoutItem Title="Cats"
                Icon="cat.png">
       <Tab>
           <ShellContent ContentTemplate="{DataTemplate views:CatsPage}" />
       </Tab>
    </FlyoutItem>
    <FlyoutItem Title="Dogs"
                Icon="dog.png">
       <Tab>
           <ShellContent ContentTemplate="{DataTemplate views:DogsPage}" />
       </Tab>
    </FlyoutItem>
</Shell>

Эквивалентно следующему:

Язык кода:javascript
копировать
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:controls="clr-namespace:Xaminals.Controls"
       xmlns:views="clr-namespace:Xaminals.Views"
       x:Class="Xaminals.AppShell">
   <ShellContent Title="Cats"
                 Icon="cat.png"
                 ContentTemplate="{DataTemplate views:CatsPage}" />
   <ShellContent Title="Dogs"
                 Icon="dog.png"
                 ContentTemplate="{DataTemplate views:DogsPage}" />
</Shell>

этотнеявное преобразованиеавтоматический Воля Каждый个 ShellContent Объект завернут в Tab объект середина, в то время как Tab затем упаковано в FlyoutItem объектсередина。

Прямо сейчас Shell серединапо умолчанию FlyoutItem, FlyoutItem / TabBar серединапо умолчанию Tab

Примечание подкласс Shell объектсерединаизвсе FlyoutItem объекты автоматически добавляются в Shell.FlyoutItems собирать, Определение коллекции Волясуществоватьвсплывающее окносередина отображает список элементов из.

Определить внешний вид FlyoutItem

добавив Shell.ItemTemplate Дополнительные атрибуты DataTemplate Настраивается для каждого FlyoutItem Появление:

Язык кода:javascript
копировать
<Shell ...>
    ...
    <Shell.ItemTemplate>
        <DataTemplate>
            <Grid ColumnDefinitions="0.2*,0.8*">
                <Image Source="{Binding FlyoutIcon}"
                       Margin="5"
                       HeightRequest="45" />
                <Label Grid.Column="1"
                       Text="{Binding Title}"
                       FontAttributes="Italic"
                       VerticalTextAlignment="Center" />
            </Grid>
        </DataTemplate>
    </Shell.ItemTemplate>
</Shell>

FontAttributes="Italic" В этом примере каждое слово отображается курсивом. FlyoutItem Название объекта:

Shell.ItemTemplate является прикрепленным атрибутом, поэтому к определенному элементу можно прикрепить разные шаблоны. FlyoutItem объект.

заменятьвсплывающее окносодержание

Всплывающее сообщение означает «агрессивнее» содержимое окна, вы можете выбрать Воля заменить его на свое собственное содержимое от Воля Shell.FlyoutContent Можетобязательностьсвойствонастраиватьдля object

Язык кода:javascript
копировать
<Shell ...
       x:Name="shell">
    ...
    <Shell.FlyoutContent>
        <CollectionView BindingContext="{x:Reference shell}"
                        IsGrouped="True"
                        ItemsSource="{Binding FlyoutItems}">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <Label Text="{Binding Title}"
                           TextColor="White"
                           FontSize="Large" />
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </Shell.FlyoutContent>
</Shell>

существоватьэтот Примерсередина,Волявсплывающее замена содержимого окнадля CollectionView,этопоказывать Понятно FlyoutItems Коллекция середина каждого предмета из названия.

Кроме того, вы можете добавить Shell.FlyoutContentTemplate Можетобязательностьсвойствонастраиватьдля DataTemplate Приходитьопределениевсплывающее окносодержание:

Язык кода:javascript
копировать
<Shell ...
       x:Name="shell">
    ...
    <Shell.FlyoutContentTemplate>
        <DataTemplate>
            <CollectionView BindingContext="{x:Reference shell}"
                            IsGrouped="True"
                            ItemsSource="{Binding FlyoutItems}">
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <Label Text="{Binding Title}"
                               TextColor="White"
                               FontSize="Large" />
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </DataTemplate>
    </Shell.FlyoutContentTemplate>
</Shell>

Выбор всплывающего элемента

Сценарий: иногда нет необходимости отображать первый по умолчанию.

первый запускиспользоватьвсплывающее окноиз Shell приложениечас,Shell.CurrentItem свойство Волянастраиватьдляподкласс Shell объектсерединаиз Нет.один FlyoutItem объект. Однако этот объект недвижимости может быть отремонтирован для другого. FlyoutItem,Как показано в следующем примере:

Язык кода:javascript
копировать
<Shell ...
       CurrentItem="{x:Reference aboutItem}">
    <FlyoutItem FlyoutDisplayOptions="AsMultipleItems">
        ...
    </FlyoutItem>
    <ShellContent x:Name="aboutItem"
                  Title="About"
                  Icon="info.png"
                  ContentTemplate="{DataTemplate views:AboutPage}" />
</Shell>

Этот пример будет CurrentItem свойствонастраиватьдляимядля aboutItem из ShellContent Объект, к которому ведет Воля, выбирается середина и показывает объект. существоватьэтот Примерсередина,неявное преобразованиеиспользуется для Воля ShellContent Объект завернут в Tab объектсередина,назадили упаковкасуществовать FlyoutItem объектсередина。

Предположим, существует файл с именем aboutItem из ShellContent объект,тогда Эквивалентиз C# Код:

Язык кода:javascript
копировать
CurrentItem = aboutItem;

существоватьэтот Примерсередина,CurrentItem свойство是существоватьподкласс Shell добрыйсерединанастраиватьиз。 Альтернативно, вы можете пройти Shell.Current 静态свойствосуществовать任何добрыйсерединанастраивать CurrentItem свойство:

Язык кода:javascript
копировать
Shell.Current.CurrentItem = aboutItem;

Видимость FlyoutItem

неожиданно возникнутьсуществоватьвсплывающее окносерединапо умолчанию Может Видеть。 Однако можно использовать FlyoutItemIsVisible свойство Воляэлемент скрытсуществоватьвсплывающее окносередина,ииспользовать IsVisible свойство Воля Это отвсплывающее окносередина Удалить:

  • Тип bool из FlyoutItemIsVisible Указывает, существует ли предмет всплывающее. окносередина但仍Может以проходить GoToAsync Метод навигации для доступа. Этот атрибут имеет значение по умолчанию для true
  • Тип bool из IsVisible Указывает, следует ли удалить элемент из визуального дерева середина, чтобы он не существовалвсплывающее. окносередина шоу. Это значение по умолчанию для true

Примечание Есть еще один Shell.FlyoutItemIsVisible Дополнительные объекты доступны по адресу FlyoutItemMenuItemTab и ShellContent на объектенастраивать该свойство。

Программно открывать и закрывать окно «финансовое окно»

Язык кода:javascript
копировать
<Shell ...
       FlyoutIsPresented="{Binding IsFlyoutOpen}">
</Shell>
Язык кода:javascript
копировать
Shell.Current.FlyoutIsPresented = false;

Нижняя панель навигации

ссылка:

Язык кода:javascript
копировать
<TabBar>
    <ShellContent Title="About" Icon="icon_about.png" Route="AboutPage" ContentTemplate="{DataTemplate local:AboutPage}" />
    <ShellContent Title="Browse" Icon="icon_feed.png" ContentTemplate="{DataTemplate local:ItemsPage}" />
</TabBar>

Визуальный осмотр, без дополнений Title, Icon будет скрыт, то в настоящее время вы можете перемещаться сюда только через код.

Язык кода:javascript
копировать
<!--
	If you would like to navigate to this content you can do so by calling
	await Shell.Current.GoToAsync("//LoginPage");
-->
<TabBar>
    <ShellContent Route="LoginPage" ContentTemplate="{DataTemplate local:LoginPage}" />
</TabBar>

одна страница

TabBar серединатолько один ShellContent,не будет отображатьсянижняя вкладка Панель навигации

Язык кода:javascript
копировать
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:views="clr-namespace:Xaminals.Views"
       x:Class="Xaminals.AppShell">
    <TabBar>
       <Tab>
           <ShellContent ContentTemplate="{DataTemplate views:CatsPage}" />
       </Tab>
    </TabBar>
</Shell>

нижняя вкладка

еслинравиться单个 TabBar Есть несколько объектов середина Tab объект, тогда Tab Рендеринг объектовдлянижняя вкладка:

Тип string из Title Свойство, определяющее заголовок вкладки. Тип ImageSource из Icon Свойства для определения значка вкладки:

если TabBar Есть более пяти извкладок,тогда покажи "еще"вкладка,Доступны для доступа другие вкладки:

Нижние и верхние вкладки

еслиодин Tab объект Есть несколько ShellContent объект, то Волясуществоватьнижняя вкладкасередина добавить одну верхнюю панель вкладки, применить По панели вкладки можно перемещаться ContentPage Объект:

Язык кода:javascript
копировать
<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:views="clr-namespace:Xaminals.Views"
       x:Class="Xaminals.AppShell">
    <TabBar>
       <Tab Title="Domestic"
            Icon="paw.png">
           <ShellContent Title="Cats"
                         ContentTemplate="{DataTemplate views:CatsPage}" />
           <ShellContent Title="Dogs"
                         ContentTemplate="{DataTemplate views:DogsPage}" />
       </Tab>
       <Tab Title="Monkeys"
            Icon="monkey.png">
           <ShellContent ContentTemplate="{DataTemplate views:MonkeysPage}" />
       </Tab>
    </TabBar>
</Shell>

Выбор вкладки

Первый запуск Shell приложениечас,Shell.CurrentItem свойство Волянастраиватьдляподкласс Shell объектсерединаиз Нет.один Tab объект. Однако этот объект недвижимости может быть отремонтирован для другого. Tab,Как показано в следующем примере:

Язык кода:javascript
копировать
<Shell ...
       CurrentItem="{x:Reference dogsItem}">
    <TabBar>
        <ShellContent Title="Cats"
                      Icon="cat.png"
                      ContentTemplate="{DataTemplate views:CatsPage}" />
        <ShellContent x:Name="dogsItem"
                      Title="Dogs"
                      Icon="dog.png"
                      ContentTemplate="{DataTemplate views:DogsPage}" />
    </TabBar>
</Shell>

Пополнить

Показать одновременно появляться、Нижняя панель навигации

ссылка:

Нет возможности напрямуюсуществоватьShellсередина,такой жечасявныйопределение FlyoutItem и TabBar могу только пройти FlyoutItem неявный эффект

Уведомление: не в FlyoutItem Использовать на FlyoutDisplayOptions="AsMultipleItems", Это приведет к первая страница、игра、канал、динамичныйтакже показатьсуществоватьсторонапоявлятьсястолбец

Язык кода:javascript
копировать
<!-- показыватьсуществовать Нижняя панель навигации -->
<FlyoutItem Title="первая страница" Icon="icon_about.png">
    <Tab Title="первая страница" Icon="icon_about.png">
        <ShellContent x:Name="HotPageItem" 
                      Название="Горячий"
                      ContentTemplate="{DataTemplate local:HotPage}" />
        <ShellContent x:Name="RecomPageItem" 
                      Название="Рекомендуется"
                      ContentTemplate="{DataTemplate local:RecomPage}" />
        <ShellContent x:Name="LastPageItem" 
                      Название="Последний"
                      ContentTemplate="{DataTemplate local:LastPage}" />
    </Tab>
    <Tab Название="Игра" Icon="icon_feed.png">
        <ShellContent ContentTemplate="{DataTemplate local:ItemsPage}" />
    </Tab>
    <Tab Название="Канал" Icon="icon_feed.png">
        <ShellContent ContentTemplate="{DataTemplate local:ItemsPage}" />
    </Tab>
    <Tab Название="динамический" Icon="icon_feed.png">
        <ShellContent ContentTemplate="{DataTemplate local:ItemsPage}" />
    </Tab>
</FlyoutItem>
<!-- показыватьсуществоватьсторонапоявлятьсястолбец -->
<FlyoutItem Название="О программе" Icon="icon_about.png">
    <ShellContent ContentTemplate="{DataTemplate local:HomePage}" />
</FlyoutItem>
<FlyoutItem Title="настраивать" Icon="icon_setting.png">
    <ShellContent ContentTemplate="{DataTemplate local:SettingPage}" />
</FlyoutItem>

Пополнить

позволятьпервая страницапо умолчанию选середина второй рекомендовать,существовать первая страница использование предмета CurrentItem

Язык кода:javascript
копировать
<Tab Title="первая страница" Icon="icon_about.png" CurrentItem="{x:Reference RecomPageItem}">
    <ShellContent x:Name="HotPageItem" 
                  Название="Горячий"
                  ContentTemplate="{DataTemplate local:HotPage}" />
    <ShellContent x:Name="RecomPageItem" 
                  Название="Рекомендуется"
                  ContentTemplate="{DataTemplate local:RecomPage}" />
    <ShellContent x:Name="LastPageItem" 
                  Название="Последний"
                  ContentTemplate="{DataTemplate local:LastPage}" />
</Tab>

Shell добавляет жесты и смахивания

ссылка:

Официально не реализовано Нижняя панель навигации параметров (включая дочернюю верхнюю панель навигации) Скользящая анимация для переключения страниц Видеть [Feature] Swipe left/right to navigate between upper/bottom tabs of Shell · Issue #12435 · xamarin/Xamarin.Forms

Xamarin.Forms скольжение, жесты

ссылка:

просмотр прокрутки ScrollView существоватьXamarin.Formsсередина,просмотр прокруткиScrollView используется для отображения длинной прокрутки контента. Хотя свойствоScrollViewizContent может иметь только одно значение, Прямо СейчасScrollView может содержать только один дочерний элемент, но на самом деле это элемент управления «один макет», специальный элемент «один измакет». существоватьиспользоватьизчасждать,ScrollView требует, чтобы родительский контейнер выделил ему фиксированный размер.,такой жечас子元素и且有固定изразмер。так,ScrollView может рассчитать сумму прокрутки исходя из их соответствующих размеров. ScrollView не только обеспечивает прежнюю сумму прокрутки ScrollXиScrollY,Также предоставляется общий объем контента ContentSize. так,Разработчики могут рассчитать ход прокрутки,показывать给пользователь。такой жечас,Используйте ScrollView, чтобы предоставить конечное событие Scrolled,Пользователям могут быть предложены,Или загрузите новый контент.

Q&A

Пополнить

Парсинг Markdown

ссылка:

V**

ссылка:

проникновение в интранет

ссылка:

Автоматическое обновление

ссылка:

Xamarin.Android получает номер предыдущей версии, когда

Android

Язык кода:javascript
копировать
public string GetVersion()
{
    // https://stackoverflow.com/questions/47353986/xamarin-forms-forms-context-is-obsolete
    var context = Android.App.Application.Context;

    return context.PackageManager.GetPackageInfo(context.PackageName, 0).VersionName;
}

Ошибка ниже,Activity наследовать Context,так выйти из activity=null

Язык кода:javascript
копировать
public string GetVersion()
{
    var activity=Xamarin.Forms.Forms.Context as Activity;
    return activity.PackageManager.GetPackageInfo(activity.PackageName, 0).VersionName;
}

iOS

Язык кода:javascript
копировать
public string GetVersion()
{
    return NSBundle.MainBundle.InfoDictionary["CFBundleShortVersionString"].ToString();
}

Установить локальный APK

Язык кода:javascript
копировать
public void InstallAPK(string filePath)
{
     try
     {
         Java.IO.File apkFile = new Java.IO.File(filePath);

         Intent intent = new Intent(Intent.ActionView);
         intent.SetFlags(ActivityFlags.NewTask);

         // Уведомление: 直接从документсередина Установить APK и Установить из менеджера загрузок середина нет то же самое
         // Получить Скачать документизUri
         if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.N)
         {
             // Android 7.0+
             Android.Net.Uri apkFileUri = Android.Support.V4.Content.FileProvider.GetUriForFile(_mContext, "github.yiyungent.onetree.fileprovider", apkFile);
             intent.AddFlags(ActivityFlags.GrantReadUriPermission);
             intent.SetDataAndType(apkFileUri, "application/vnd.android.package-archive");
         }
         else
         {
             Android.Net.Uri apkFileUri = Android.Net.Uri.FromFile(apkFile);
             intent.SetDataAndType(apkFileUri, "application/vnd.android.package-archive");
         }
         _mContext.StartActivity(intent);
     }
     catch (Exception ex)
     {

     }
}

> AndroidManifest.xml

Язык кода:javascript
копировать
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="0.4.2" package="github.yiyungent.onetree" android:installLocation="auto">
  <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
  <application android:label="OneTree" android:theme="@style/MainTheme">
    <provider android:name="android.support.v4.content.FileProvider" android:authorities="github.yiyungent.onetree.fileprovider" android:exported="false" android:grantUriPermissions="true">
      <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
    </provider>
  </application>
  <!-- доступ Разрешения на состояние сети -->
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  <!-- 读Писать Разрешения на внешнее хранилище -->
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  <!-- доступ Сетевые разрешения -->
  <uses-permission android:name="android.permission.INTERNET" />
  <!-- существоватьSDCardсерединасоздаватьиудалитьдокумент Разрешения -->
  <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
  <!-- Разрешить установку пакетов из неизвестных источников -->
  <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
</manifest>

Resources/xml/file_paths.xml

Язык кода:javascript
копировать
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
  <!--Context.getFilesDir() 位于/data/data/Установить Оглавление-->
  <files-path name="internalPath" path="file" />
  <!--Context.getCacheDir()-->
  <cache-path name="cachePath" path="file" />
  <!--Environment.getExternalStorageDirectory()-->
  <external-path name="externalPath" path="file" />
  <!--Context.getExternalFilesDir(null)-->
  <external-files-path name="externalFPath" path="file" />
  <root-path
          name="root-path"
          path="." />
</paths>

ссылка:

  • https://stackoverflow.com/questions/54421242/how-to-make-xamarin-forms-app-auto-updated
  • https://stackoverflow.com/questions/58409164/xamarin-display-notification-in-notification-bar-once-the-file-is-downloaded

Изменения разрешений для Android8.0 и выше,Загрузите и установите установочный пакет назад из нравитьсяapk.,Во-первых, вам необходимо подтвердить, есть ли у вас разрешение на установку приложения из неизвестных источников.

Во-первых, вам необходимо добавить следующие разрешения в файл манифеста:

Язык кода:javascript
копировать
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

На Android 8 или выше код Intent вызывает открытие apk, но интерфейс установки не вызывается.

решать:

Язык кода:javascript
копировать
//Загружаем на локальный диск и выполняем установку
private void InstallAPK()
{
    // Получить Скачать документизUri
    Android.Net.Uri downloadFileUri = _downloadManager.GetUriForDownloadedFile(_downloadId);
    if (downloadFileUri != null)
    {
        Intent intent = new Intent(Intent.ActionView);
        intent.SetDataAndType(downloadFileUri, "application/vnd.android.package-archive");
        //intent.AddFlags(ActivityFlags.NewTask);

        intent.SetFlags(ActivityFlags.NewTask);
        intent.AddFlags(ActivityFlags.GrantReadUriPermission);

        _mContext.StartActivity(intent);
    }
}

Примечание. Оба предложения ниже должны быть включены.

Язык кода:javascript
копировать
intent.SetFlags(ActivityFlags.NewTask);
intent.AddFlags(ActivityFlags.GrantReadUriPermission);

Разрешения Уведомление:

Язык кода:javascript
копировать
<!-- Разрешить установку пакетов из неизвестных источников -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

такой жечас,Помнитьсуществоватькодсерединапроситьэтот Разрешения

Часто используемые пакеты

ссылка:

Firebase

ссылка:

Дизайн интерфейса

ссылка:

настраивать Button IsEnabled="False",Волясделаю Button Вернуться к стилю по умолчанию

ссылка:

Android 11 доступ к каталогу Android/data

ссылка:

JarBinding Аврора Пуш

ссылка:

Заставка Android Заставка

ссылка:

Уведомление:

splash_screen.xml По умолчанию файл имеет значение TransformFile,Это приведет к тому, что файл перестройки не найден.

решать:

Изменить на: AndroidResource

Прямо сейчас,OneTree.Android.csproj,Его середина такова:

Язык кода:javascript
копировать
<ItemGroup>                                                          
  <AndroidResource Include="Resources\drawable\splash_screen.xml" /> 
</ItemGroup>                                                         

Выберите файл

ссылка:

Загрузить файлы

ссылка:

Android 9.0 требует HTTPS

ссылка:

AndroidManifest.xml

Язык кода:javascript
копировать
<application 
    android:label="@string/ApplicationName" 
    android:theme="@style/MainTheme" 
    android:icon="@mipmap/icon"
    android:networkSecurityConfig="@xml/network_security_config">
  </application>

xml/network_security_config.xml

Язык кода:javascript
копировать
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <!-- Android 9.0+ 必须использоватьHTTPS -->
  <base-config cleartextTrafficPermitted="true" />
</network-security-config>

Потяните вниз, чтобы обновить, потяните вверх, чтобы загрузить

ссылка:

Пользовательские элементы управления

ссылка:

HTTP Listener

ссылка:

UI

ссылка:

разделительная линия

ссылка:

App.xaml

Язык кода:javascript
копировать
<Style x:Key="Separator" TargetType="BoxView">
    <Setter Property="HeightRequest" Value="1" />
    <Setter Property="HorizontalOptions" Value="FillAndExpand" />
    <Setter Property="Color" Value="Gray" />
    <Setter Property="Margin" Value="0, 5, 0, 5" />
    <Setter Property="Opacity" Value="0.5" />
</Style>
Язык кода:javascript
копировать
<BoxView Style="{StaticResource Separator}" />

Опубликовано в Кулан

ссылка:

Visual Stuido 2019 Найти документ с подписью yiyun.keystore

1. Щелкните правой кнопкой мыши, чтобы войти в «Просмотр архивов».

если не было создано ранее apk (Архив), запустите его один раз Archive

archive.xml

Язык кода:javascript
копировать
<?xml version="1.0" encoding="utf-8"?>
<Archive>
  <Name>OneTree</Name>
  <PackageName>github.yiyungent.onetree</PackageName>
  <PackageVersionCode>1</PackageVersionCode>
  <PackageVersionName>0.4.0</PackageVersionName>
  <PackageFormat>apk</PackageFormat>
  <CreationDate>637619313170861804</CreationDate>
  <SolutionName>OneTree.App</SolutionName>
  <SolutionPath>F:\Com\me\Repos\OneTree.App\OneTree.App.sln</SolutionPath>
  <Status></Status>
  <Configuration>
    <DebugMode>false</DebugMode>
  </Configuration>
  <Comment />
  <LastUsedKeystore>C:\Users\yiyun\AppData\Local\Xamarin\Mono for Android\Keystore\yiyun\yiyun.keystore</LastUsedKeystore>
  <TimeStampingAuthority />
  <LastInsightsUploadDate>0</LastInsightsUploadDate>
</Archive>

Чтосередина LastUsedKeystore Прямо сейчасдлязнакдокументпуть

используйте этот знак-документ, чтобы охладить подарок из Не знакapk ( CoolApkDevVerify_no_sign.apk ) подпись, генерировать знакиз signed.apk

Язык кода:javascript
копировать
jarsigner -verbose -keystore yiyun.keystore -signedjar signed.apk CoolApkDevVerify_no_sign.apk yiyun
Язык кода:javascript
копировать
jarsigner -verbose -keystore [Your signature storage path] -signedjar [signed filename] [unsigned filename] [Your alias key]

Пополнить:

Проверять alias key,Что实就是тыкогдачассоздаватьсекретный ключчасизпользовательимя

Язык кода:javascript
копировать
keytool -keystore yiyun.keystore -list  -v
Язык кода:javascript
копировать
keytool -keystore [your key store] -list -v

yiyun.keystore: представляет знак документа вашего проекта. подписанный.apk: представляет ваш пакет apkiznak. CoolApkDevVerify_no_sign.apk: предоставляет вам пакет от имени CoolApkDevVerify_no_sign.apk. Введите приведенную выше команду назад, и ваш рабочий стол будет загружен в Kuan isapk и станет знаком (а установочный пакет isниктознак, предоставленный iKuan, имеет примерно такой же размер)

Фактически, это будет Крутая безопасность для вас CoolApkDevVerify_no_sign.apk , используйте секретный ключ, который вы дали себе изapkзнакиз, а затем дайте этот проверочный apk Подпишите это

Собственно, именно того, что ниже, у меня нет настроек, поэтому его у меня нет.

WebView

ссылка:

WebView взаимодействует с JavaScript

ссылка:

1.js -> WebView: console.log
Язык кода:javascript
копировать
// Javascript код
console.log('{"width": "750"}');
Язык кода:javascript
копировать
// C#
public class TorchWebChromeClient : Android.Webkit.WebChromeClient
{

    public override void OnConsoleMessage(string message, int lineNumber, string sourceID)
    {
        // message Прямо сейчасдля JS Сообщение передается, и сообщение оценивается для определения метода вызова.
        base.OnConsoleMessage(message, lineNumber, sourceID);
    }

}
2.js -> WebView: JSBridge

самый распространенный метод,Удобно и лаконично,Но единственныйиз Недостатком являетсясуществовать 4.2 В системе ниже есть уязвимости

Добавьте сопоставление объектов с помощью метода addJavascriptInterface.

Этот метод на самом деле предназначен для js экологический контекст ( Window ) вводить для js вызов Фактически, следующее window середина Введенный jsBridge.invokeAction и invokeCSharpAction,назад — это первое из инкапсуляции,实际начальствоты也Может以直接использовать jsBridge.invokeAction,Но вы должны обеспечить существование OnPageFinished назад

Язык кода:javascript
копировать
public class JSBridge : Java.Lang.Object
{
    readonly WeakReference<HybridWebViewRenderer> hybridWebViewRenderer;

    public JSBridge(HybridWebViewRenderer hybridRenderer)
    {
        hybridWebViewRenderer = new WeakReference<HybridWebViewRenderer>(hybridRenderer);
    }

    // Открытое имя метода: invokeAction
    [JavascriptInterface]
    [Export("invokeAction")]
    public void InvokeAction(string data)
    {
        HybridWebViewRenderer hybridRenderer;

        if (hybridWebViewRenderer != null && hybridWebViewRenderer.TryGetTarget(out hybridRenderer))
        {
            // вызов WebView
            ((HybridWebView)hybridRenderer.Element).InvokeAction(data);
        }
    }
}
Язык кода:javascript
копировать
[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace TorchView4Droid.Components
{
   public class HybridWebViewRenderer : WebViewRenderer
    {
        const string JavascriptFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}";
       
		protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null)
            {
                // Unsubscribe from event handlers

                Control.RemoveJavascriptInterface("jsBridge");
                ((HybridWebView)Element).Cleanup();
            }
            if (e.NewElement != null)
            {
				// 1.WebViewClient
                var webViewClient = new JavascriptWebViewClient(this, $"javascript: {JavascriptFunction}");
                Control.SetWebViewClient(webViewClient);
                // незащищенныйсуществовать jsBridge на объекте
                // Итак, наконец: jsBridge.invokeAction
                Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
            }
        }
    } 
}
Язык кода:javascript
копировать
public class JavascriptWebViewClient : FormsWebViewClient
{
    string _javascript;

    public JavascriptWebViewClient(HybridWebViewRenderer renderer, string javascript) : base(renderer)
    {
        _javascript = javascript;
    }

    public override void OnPageFinished(WebView view, string url)
    {
        base.OnPageFinished(view, url);
        // Инкапсулированная функция существует здесь Гарантировано выполнение один раз для инъекции
        view.EvaluateJavascript(_javascript, null);
    }
}

js вызовC#

Язык кода:javascript
копировать
function invokeCSCode(data) {
    try {
        log("Sending Data:" + data);
        invokeCSharpAction(data);
    } catch (err) {
        log(err);
    }
}
3. js -> WebView: WebViewClient перехватывать url

недостаток: Протокол ограничений должен быть задокументирован в одной спецификации документа, и js Не могу стоять Прямо сейчас获取 C# из возвращаемого значения, обязательно C# снова возьмите инициативу в свои руки js передать возвращаемое значение

Язык кода:javascript
копировать
public class JavascriptWebViewClient : FormsWebViewClient
{
    public override bool ShouldOverrideUrlLoading(WebView view, IWebResourceRequest request)
    {
        // перехватыватьurl, исследовать Url.Scheme 是否длятыдляjsвызовопределениеиз Scheme
        if (request.Url != null && request.Url.Scheme != null && request.Url.Scheme.ToLower() == "js")
        {
            // вызов C#
            // Можно получить из Query серединаанализироватьпереданные данные
            var queryPars = request.Url.QueryParameterNames;
            
            // Пример: Открыть локальную страницу
            // url = "js://openActivity?arg1=111&arg2=222"
            / ...
        }
        
		return base.ShouldOverrideUrlLoading(view, request);
    }
}
Язык кода:javascript
копировать
// JavaScript
function openActivity(){
    document.location = "js://openActivity?arg1=111&arg2=222";
}

недостаток: Не могу получить это C# возвращаемое значение,

нравиться js Хотите получить возвращаемое значение метода, могу только пройти WebView из loadUrl метод для выполнения js 方法把возвращаемое значение传递回去,Связанныйизкод如Вниз:

Язык кода:javascript
копировать
webView.LoadUrl("javascript:returnResult(" + result + ")");
Язык кода:javascript
копировать
// JavaScript
function returnResult(result){
    alert("result is" + result);
}
4.js -> WebView: WebChromeClient три методаперехватыватьинформация

prompt Метод диалогового окна может возвращать строковый тип возвращаемого значения,недостаток: Трудно сформулировать соглашение.,Требуется подробная документация,Но проблемы уязвимости не будет.

перехватывать js серединаиз Существует несколько методов подсказки, то есть несколько стилей диалоговых окон. js середина имеет три общих метода диалога:

  • OnJsAlert Метод заключается в появлении всплывающего окна с предупреждением, обычно существующего. Android серединадля Тост, добавленный в текст существования;
  • OnJsConfirm отображает окно подтверждения и возвращает логическое значение. Это значение можно использовать для определения необходимости подтверждения или отмены при нажатии. True означает, что было нажато подтверждение, а false означает, что была нажата кнопка отмены.
  • OnJsPrompt Появится поле ввода, нажмите «Подтвердить», чтобы вернуться к значению поля ввода серединаиз, нажмите «Отмена», чтобы вернуться. null。
Язык кода:javascript
копировать
// JavaScript
function clickPrompt(){
    // преимущество: Могу получить это C# возвращаемое значение метода
    var result = prompt("js://openActivity?arg1=111&arg2=222");
    alert("open activity " + result);
}
Язык кода:javascript
копировать
public class TorchWebChromeClient : Android.Webkit.WebChromeClient
{
    #region js Три диалоговых окна

    public override bool OnJsAlert(WebView view, string url, string message, JsResult result)
    {
        return base.OnJsAlert(view, url, message, result);
    }

    public override bool OnJsConfirm(WebView view, string url, string message, JsResult result)
    {
        return base.OnJsConfirm(view, url, message, result);
    }

    public override bool OnJsPrompt(WebView view, string url, string message, string defaultValue, JsPromptResult result)
    {
        // Уведомление: js Передайте данные о существовании message
        // message = "js://openActivity?arg1=111&arg2=222"
        Android.Net.Uri uri = Android.Net.Uri.Parse(message);
        string scheme = uri.Scheme;
        if (scheme != null && scheme.ToLower() == "js")
        {
            IList<string> queryPars = uri.QueryParameterNames?.ToList();


            // Представляет собой завершение внутренней обработки приложения.
            result.Confirm("success");

            return true;
        }

        return base.OnJsPrompt(view, url, message, defaultValue, result);
    }

    #endregion
}

только OnJsPrompt Метод может возвращать строковый тип из значения, установленного в существующем виде. result (JsPromptResult) середина,таквыбиратьперехватыватьэто

5.WebView -> js: webView.LoadUrl

недостаток: C# вызов js ,Не могу стоять Прямо сейчас获取 jsiz возвращаемое значение, могу только пройти js снова вызов C# передать возвращаемое значение, loadUrl изExecution приведет к однократному обновлению страницы

Язык кода:javascript
копировать
// C#
mWebView.LoadUrl("javascript:show(" + result + ")");
Язык кода:javascript
копировать
// JavaScript
function show(result){
    alert("result"=result);
    return "success";
}

Уведомление Имя метода соответствует кроме,js извызов должен существовать обратный вызов функции WebViewClient.OnPageFinished для вызова,В противном случае это потерпит неудачу.

6. WebView -> js: webView.EvaluateJavascript

Google существовать Android4.4 для Мы добавили новый метод один, этот метод лучше, чем loadUrl Этот метод более удобен и краток, и он лучше, чем loadUrl более эффективен, потому что loadUrl при выполнении страница будет обновлена ​​один раз, но этот метод не будет, потому что этот метод существует 4.4 Версия была представлена ​​только из,так我们использоватьизчасждать需хотеть添加版本изсуждение

Язык кода:javascript
копировать
string jsFuncStr = "";
if ((int)Build.VERSION.SdkInt < 18)
{
    webView.LoadUrl(jsFuncStr);
}
else
{
    var jsCallback = new JsFuncValueCallback();
    webView.EvaluateJavascript(jsFuncStr, jsCallback);
}
Язык кода:javascript
копировать
#region JsFuncValueCallback
public class JsFuncValueCallback : Android.Webkit.IValueCallback
{
    public void OnReceiveValue(Object? value)
    {
      // value для js Возврат результатов

      // Конвертировать для string Метод записи происходит из: Xamarin.Forms.Platform.Android.JavascriptResult.
      string data = ((Java.Lang.String)value)?.ToString();

      // TODO: js Обработка возвращаемого значения
    }
        
    // ...
}
#endregion

Как правило, наиболее распространенным методом является первый метод.,Но первый метод более затруднителен для получения возвращаемого значения.,Второй метод был представлен в версии 4.4.,Таким образом, ограничения относительно велики.

WebView загружает локальный HTML

Вариант 1:

Язык кода:javascript
копировать
file://xxxx/index.html

Категорически не рекомендуется

Вариант 2: существовать本地запускатьодин Веб-сервер, прослушивайте определенный порт, используйте URL-адрес http://localhost:12531

Вариант 3:

ссылка:

Настройте префикс URL-адреса или HTTP Url.Scheme, Url.Host, затем передайте override WebViewClient ,перехватыватьurlпросить

Язык кода:javascript
копировать
public override WebResourceResponse ShouldInterceptRequest( WebView view, IWebResourceRequest request ) {
}

Failed to decode downloaded font: <URL>

ссылка:

Чтение и запись двоичных файлов в текстовом режиме может привести к повреждению содержимого. Двойной метод очень прост: при чтении документа все содержимое документа будет считано без изменений. При записи содержимое буфера памяти также будет записано в документсередина без изменений.   Текстовый режим нет то же самое Понятно,существовать Писатьдокументчас,Будет ли Воля символ новой строки CRLF (0x0D 0x0A) все преобразуются в один из0x0A, и когда встречается конечный символ CTRLZ (0x1A), считается, что документ закончился. Соответственно, при записи документа Волявсеиз0x0A будет заменено на 0x0D0x0A. Поэтому при открытии двойного документа в текстовом режиме легко получить неполное прочтение документа или неправильное содержание из-за ошибок. Прямо сейчас Используйте текстовый режим, чтобы открыть текстдокумент,Также будьте осторожны, используйте,напримеркопироватьдокумент,Не следует использовать текстовый режим.

Resource interpreted as Stylesheet but transferred with MIME type text/plain: "<URL>".

Java.Lang.IllegalStateException: AssetInputStream is closed

Язык кода:javascript
копировать
{Java.Lang.IllegalStateException: AssetInputStream is closed
  at Java.Interop.JniEnvironment+InstanceMethods.CallNonvirtualIntMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x0008e] in <8b3b636835d84984ba4604c1f57b1983>:0 
  at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeNonvirtualInt32Method (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x0001f] in <8b3b636835d84984ba4604c1f57b1983>:0 
  at Android.Content.Res.AssetManager+AssetInputStream.Read (System.Byte[] b, System.Int32 off, System.Int32 len) [0x00052] in <44e54a86dea24313a2bdb807df77c27a>:0 
  at Android.Runtime.InputStreamInvoker.Read (System.Byte[] buffer, System.Int32 offset, System.Int32 count) [0x00006] in <44e54a86dea24313a2bdb807df77c27a>:0 
  at System.IO.Stream.CopyTo (System.IO.Stream destination, System.Int32 bufferSize) [0x0001f] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/external/corert/src/System.Private.CoreLib/shared/System/IO/Stream.cs:179 
  at System.IO.Stream.CopyTo (System.IO.Stream destination) [0x00007] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/external/corert/src/System.Private.CoreLib/shared/System/IO/Stream.cs:168 
  at (wrapper remoting-invoke-with-check) System.IO.Stream.CopyTo(System.IO.Stream)
  at TorchView.WebServer.TaskProc (System.Object obj) [0x000ac] in F:\Com\me\Repos\TorchView\src\TorchView\WebServer.cs:144 
  --- End of managed Java.Lang.IllegalStateException stack trace ---
java.lang.IllegalStateException: AssetInputStream is closed
	at android.content.res.AssetManager$AssetInputStream.ensureOpen(AssetManager.java:1364)
	at android.content.res.AssetManager$AssetInputStream.read(AssetManager.java:1303)
}

Пакет apk

ссылка:

Укажите значок

ProGuard

Настройте ProGuard

Альтернативно добавьте На фигуру ProGuard файл конфигурации для реализации ProGuard Инструменты и больше контроля. Например, вы можете захотеть сохранить явное уведомление из класса. ProGuard。 Для этого создайте новый .cfg документ,исуществовать Обозреватель решений из панели свойств серединного приложения ProGuardConfiguration Операция сборки:

Например, если используется Tencent Bugly, то

  • Пожалуйста, избегайте путаницы. Ошибка существования Proguard документсередина добавляет следующую конфигурацию:
Язык кода:javascript
копировать
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}

для большинства Xamarin.Android Приложение, Xamarin.Android Предоставляется по умолчанию ProGuard Конфигурациядокументдостаточныйудалитьвсе(только)еще нетиспользоватьизкод。 нравитьсяхотеть Проверятьпо умолчанию ProGuard конфигурация, пожалуйста, откройте **obj_xamarin.cfg** В издокументе.

Имейте в виду, что этот файл конфигурации не заменяет файл Xamarin.Android proguard_xamarin.cfg, поскольку ProGuard будет использовать оба файла.

переписываться OneTree.Android.csproj

Язык кода:javascript
копировать
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>portable</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release</OutputPath>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <AndroidManagedSymbols>true</AndroidManagedSymbols>
    <AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
    <AotAssemblies>false</AotAssemblies>
    <EnableLLVM>false</EnableLLVM>
    <AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
    <BundleAssemblies>true</BundleAssemblies>
    <AndroidLinkTool>proguard</AndroidLinkTool>
</PropertyGroup>
Язык кода:javascript
копировать
<ItemGroup>
	<ProguardConfiguration Include="ProGuard.cfg" />
</ItemGroup>

Защита приложений

Отключить отладку

существовать Android При разработке приложения вы будете использовать Java Протокол линии отладки (JDWP) Выполните отладку. Это технология, которая позволяет adb и другие инструменты для целей отладки JVM коммуникация. Пара по умолчанию Xamarin.Android приложениеиз отладочной версии включено JDWP。 Хотя JDWP Существующий процесс разработки середина очень непродолжителен, но он может вызвать проблемы с безопасностью выпущенного изприложения.

важный Пожалуйста, всегда отключайте состояние отладки выпущенного приложениясерединаиз, так как если оно не отключает это состояние, то это возможно (проходить JDWP) получено Java 进程изполностьюдоступ Разрешенияисуществоватьприложениеизначальство Вниз文серединавыполнять произвольныйкод。

Android Список содержит android:debuggable Свойство, определяющее возможность отладки приложения. Воля android:debuggable свойствонастраиватьдля false Это считается хорошей практикой. Самый простой способ сделать это — существовать AssemblyInfo.cs середина Добавить условиякомпилироватьзаявление:

Язык кода:javascript
копировать
#if DEBUG
[assembly: Application(Debuggable=true)]
#else
[assembly: Application(Debuggable=false)]
#endif

Объединение сборок в машинный код

этот选项启用час,сборкавстреча В комплекте с этой машиной共享Библиотекасередина。 Это позволяет сжать сборку и уменьшить .apk документизразмер。 Сжатие сборки также обеспечивает минимальную форму запутывания; на такое запутывание не следует полагаться;

Этот вариант требует Enterprise лицензия,толькокогда“использовать Быстрое развертывание”Запрещатьчас才Может用。 “Объединение сборок в машинный «существовать код» отключен по умолчанию.

пожалуйста Уведомление,“В комплекте с этой машинойкод”选项执行Нет意味着сборкавстречакомпилироватьк этой машинекодсередина。 нет в наличии AOT-компиляцияВолясборкакомпилироватьдлялокальная машинакод。

переписываться OneTree.Android.csproj

Язык кода:javascript
копировать
<PropertyGroup>
	<BundleAssemblies>true</BundleAssemblies>
</PropertyGroup>

Уведомление: Я пробовал назад, и размер APK варьировался от 14MB увеличить до 25МБ, не знаю почему, не уменьшилось, а увеличилось.

Уведомление: Обнаружить,такой же一套код,Та же конфигурация, что и у одного Пакета., Visual Studio 2019 Professional Объем упаковки 13.5 MB Visual Studio 2019 Enterprise Объем упаковки 19.2 MB, Собственно корпоративная версия Объем упаковка больше, в то время как только Enterprise Edition имеет into Native Code

Настроить компоновщик

Примечание: использование ProGuard с компилятором DEX D8 больше не поддерживается.

Язык кода:javascript
копировать
Using ProGuard with the D8 DEX compiler is no longer supported. Please set the code shrinker to 'r8' in the Visual Studio project property pages or edit the project file in a text editor and set the 'AndroidLinkTool' MSBuild property to 'r8'.

решать:

ProGuard нельзя использовать с d8 используются вместе или использовать ProGuard,Просто измените это d8 для dx,

Или не используйте его ProGuard,Скорее использовать r8 и d8

изменение пароля хранилища ключей

ссылка:

Visual Studio AppCenter

ссылка:

Xamarin в сочетании с действиями GitHub

ссылка:

ссылка

Спасибо за помощь!

Автор этой статьи: yiyun

Ссылка на эту статью: https://moeci.com/posts/category-dotnet/xamarin/

Заявление об авторских правах: Если не указано иное, во всех статьях этого блога используются BY-NC-SA Лицензионное соглашение. При перепечатке просьба указывать источник!

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose