Из коробки exe/appimage, в котором внутри нужные классы для рантайма (и только они). Но руками прикручивается и фулл натив, просто больше архитектурных вопросов решать придется
Например вот фулл натив для десктопа, без всяких фатжаров под капотом
нет, в .net под это уже сделали новую реализацию aot. Собирается полностью нативный бинарник.
С официальной статьи Microsoft про MAUI
Это неправда.
"macOS apps built using .NET MAUI use Mac Catalyst, a solution from Apple that brings your iOS app built with UIKit to the desktop, and augments it with additional AppKit and platform APIs as required"
В Джаве для этого есть Spring Data JDBC. Те же автоматическая десериализация, готовый круд, декларативные транзакции и тд, но запросы пишутся руками. Не отбирает контроль, облегчает жизнь
Но большинству макак слишком сложно, проще 100+ аннотаций для JPA навесить на энтити и потом месяц пытаться понять, почему все это работает не так, как ожидалось
Мне больше нравится подход SQLDelight с мультиплатформы Котлина и JOOQ из Джавы. Когда разработчик руками пишет SQL-запросы, а библиотека по ним и миграциям генерирует энтити и методы в репозиториях для вызова этих запросов. Получается "ORM наоборот", который и не отбирает контроль, и не генерирует всякую хрень (чем славится тот же Hibernate), и при этом облегчает работу
Не могу ничего сказать, т.к. никогда не писал на шарпе в целом и Xamarin в частности.
НО: Xamarin в целом же заброшен, насколько до меня слухи доходили. Теперь будет MAUI, по любимой традиции шарпа постоянно бросать "революционные" технологии и заменять их "еще более революционными", чтобы потом забросить уже их. И работать он будет через Моно (везде, кроме винды), а на MacOS вообще через эмулятор ios. Т.е. никаким фулл нативом, возможностью юзать нативные либы платформ и тд даже не пахнет. Будет очередной React Native, но на шарпе
С учетом такого будущего сравнивать не вижу смысла)
В КМ приложение бьется на модули/sourceset-ы (иерархию разработчик выбирает сам), один из которых является кроссплатформерным, а остальные - для каждой платформы индивидуально.
Поддерживается множество платформ, включая WearOS, WatchOS и TVOS
Обычно всё, кроме UI, выносят в шейред/коммон модуль, а для каждой платформы делают UI отдельно. Но с недавним выходом Compose Multiplatform можно делать UI для Андроида и десктопа один раз, если хочется. В данный момент идет разработка (экспериментальный релиз доступен) Multiplatform Compose (не путать с Compose Multiplatform, его потом собираются вливать туда), который должен позволить писать UI под IOS точно так же, как под Android. С наличием Compose Multiplatform, позволяющим писать под Android и десктоп один раз, дублирование будет только в вебе
Т.е., если нам надо сделать приложение, работающее везде (десктоп, андроид, айос, веб), то это будет 1 общий модуль с бизнес-логикой, DI, логикой хранения данных и тд, и по 1 модулю для каждой из платформ, где будет UI для них
Визуализация возможной иерархии модулей
При этом зависимости каждого модуля мы выбираем самостоятельно. Например, при сборке под айос, код на Котлине превратится в библиотеку на Swift, что позволит разрабатывать UI на Swift тем, кто привык работать с айос, использовать их нативные библиотеки и тд. В вебе можно писать как на самом Котлине (его обертке вокруг Compose), для знакомых с разработкой на андроиде, так и на обертке на Котлине вокруг Реакта, так и на чистом нативном Реакте на жс/тс
Все это дает несколько плюсов и один минус
Минус:
Есть дублирование в виде UI-кода под разные платформы. Частично решается библиотеками, но все равно что-то на визуальной части будет дублироваться, что усложнит поддержку. В данный момент эту проблему как раз и решают, растаскивая Compose на все платформы, куда дотягиваются
Плюсы:
Полный натив. Никакого лишнего движка рендера, как в React Native или Flutter, никакого WebView, как в Ionic. На Андроиде будет фулл натив андроид приложение, на свифте - фулл натив свифт приложение, на десктопе - бинарник на жвм или фулл натив на выбор, в вебе - фулл натив жс.
Возможность не-кроссплатформерным разработчикам делать UI под каждую платформу без необходимости уметь в эту кроссплатформерную разработку. Например, в команде есть человек, знающий только свифт. Никто не мешает ему делать UI под айос на этом свифте для вашей кроссплатформы, как он привык и с какими угодно либами свифта (т.к. все, кроме UI, превращается просто в библиотеку)
Разработчик сам определяет зависимости каждого модуля. То есть можно спокойно использовать фулл нативные библиотеки каждой платформы только для нее, не полагаясь на наличие каких-то там нужных плагинов. Например, в вебе тот же реакт и библиотеки для него - сколько угодно. На андроиде библиотеки только для андроида - пожалуйста
Разработчик сам определяет еще и какой код нужно выносить на мультиплатформу, а какой оставить только для конкретной. Это делается с помощью иерархии модулей и связки expect/actual. Если хочется, никто не заставляет шарить все, кроме UI. Можно и больше кода вынести на конкретные платформы. Собственно, картинка выше это и отображает. Возможность задать иерархию какого угодно уровня
Пример связки expect/actual
Связка expect/actual для разделения объявлений и платформозависимых реализацийНа примере генерации UUID
Есть уже далеко не малое количество библиотек с поддержкой Kotlin Multiplatform, позволяющих 80-90% кода, включая UI, вынести в коммон/шейред модуль. Базы данных, веб-клиенты, DI, вьюмодели, реклама, безопасность, аналитика и прочее. Есть даже целый проект https://arkivanov.github.io/Decompose/, следующий парадигме pluggable ui для разделения кода
Отвечая на Ваши вопросы:
Сколько "весит" минимальное приложение?
Столько же, сколько и нативное под эту платформу. Kotlin Multiplatform просто собирает модули в библиотеку и позволяет подключить ее при разработке UI, чтобы не писать все, кроме UI, заново.
Реально ли в действиетльности написать кроссплатформенное приложение или всё-таки потребуются костыли под разные ОС?
Потребуется как минимум часть UI писать под каждую платформу отдельно. Остальное можно полностью вынести в кроссплатформу, если надо. Если не надо, можно не выносить или вынести часть
Если костыли нужны, на сколько сложно их добавлять и на каких языках это делается?
На нативных для каждой платформы. Андроид и WearOS - Java/Kotlin, Веб - Kotlin/JS и/или просто JS/TS, Ios/TVOS/WatchOS - Swift, Десктоп на жвм - Java/Kotlin. Это позволяет использовать нативные библиотеки и не задумываться, сделали уже нужный плагин или нет
Например, приложение под iOS и Android будет иметь полностью общий код? И насколько сложно поддерживать потом приложение?
Не совсем общий. Как минимум часть UI будет на разных языках (Kotlin/Swift). Поддержку требовать будут нативные фичи каждой платформы (которые Вы сами решаете, использовать или нет) и сам этот UI
Прикрепляю пару кроссплатформерных проектов для примера
Поддержка Android, IOS, WearOS, WatchOS, Desktop, Web (React)
Итого, это не имеющая на данный момент аналогов технология (по крайней мере из того, что на слуху), позволяющая делать мультиплатформерные клиентские приложения с полным нативом и минимальным дублирование кода (а в перспективе и вообще без него), с сохранением полной свободы творчества и возможностей разработчика, при этом использующая максимально привычный и общепринятый инструментарий
Во-первых, UI для ios и android разный, т.е. все равно будет дублирование. Во-вторых, в последний раз, когда я смотрел, Flutter Desktop и Flutter Web были просто ужасны, это был просто тот же самый мобильный UI, просто растянутый на десктопный экран.
В третьих, я честно не знаю, зачем использовать Flutter со всеми его проблемами + локальным языком, когда есть тот же Kotlin Multiplatform, позволяющий то же, только с гораздо меньшими костылями, нативно и на более популярном и общепринятом языке
Вы использовали тупль, который тут хорошо подходит, да. Но если переменных больше 2? Если надо работать с переменными, которые по смысле не объединить в одну структуру?
Вы говорите про synchronized, который синхронизирует по объекту. А я говорю про реализации интерфейса Lock из пакета java.util.concurrent.locks. Например ReentrantLock
Вот пример с аналогичным для Сишных мьютексов кодом на Джаве
class CommonResource {
int x = 0;
}
public class Main {
public static void main(String[] args) {
CommonResource resource = new CommonResource();
Lock locker = new ReentrantLock();
for (int i = 1; i < 6; i++) {
Thread t = new Thread(() -> {
locker.lock();
try {
resource.x = 1;
for (int j = 1; j < 5; j++) {
System.out.printf("%s %d %n", Thread.currentThread().getName(), resource.x);
resource.x++;
Thread.sleep(100);
}
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
finally {
locker.unlock();
}
});
t.setName("Thread " + i);
t.start();
}
}
}
Возникает интересный вопрос: а если нам надо свопнуть два значения с помощью мьютексов, как это нормально реализовать в Расте? Ну то есть через мьютексы в Си или локи в Жаве можно просто объявить кусок кода однопоточным и сделать там, что угодно
Но в расте, получается, придется делать по мьютексу на каждую используемую переменную. А если это не своп и их не 2, а больше? Оптимизационная проблема получается
С этим языком знаком плохо, поэтому буду рад, если подскажете, как это можно сделать лучше
Но на данный момент ничего лучше следующего не приходит на ум, а это не очень:
use std::mem;
use std::sync::Mutex;
struct Data1 {
m_x: Mutex<usize>,
}
struct Data2 {
m_y: Mutex<usize>,
}
fn swap(src: Data1, dest: Data2) {
let mut lock_src = src.m_x.lock().unwrap();
let mut lock_dest = dest.m_y.lock().unwrap();
mem::swap(&mut *lock_src, &mut *lock_dest);
println!("was 5 now {}", (*lock_src));
println!("was 10 now {}", (*lock_dest));
}
fn main() {
let data1 = Data1 { m_x: Mutex::new(5) };
let data2 = Data2 { m_y: Mutex::new(10) };
swap(data1, data2);
}
При использовании этого решения натыкался на проблему: при наличии в контроллере более одного маппинга на один и тот же адрес, но с разными параметрами, в Сваггере в итоге все эти маппинги превращались в один эндпоинт, описание, схема и прочее которого случайно бралось от одного из маппингов, а в параметрах были абсолютно все параметры из всех маппингов по этому адресу, и с пометкой required (даже если в самих маппингах явно стоит required = false)
Судя по всему, он просто мержит все эндпоинты на основании их адреса, а не методов с маппингами. В итоге вместо нескольких нормальных маппингов получается один, в который навалено все подряд в случайном порядке, да еще и вводящие в заблуждение параметры указаны
Слез с винды года 4 назад, полет нормальный. Играть или работать секретаршей не так удобно, зато для разработки и остальных нужд - золото. При этом, если мння что-то не устраивает в системе, я могу это изменить
а если нужны специфические фичи винды или мака, я просто делаю виртуалку и пробрасываю туда железо (чего ни винда, ни мак не умеют). Только недавно Big Sur поставил и обновил до Monterey в виртуалке, XCode работает, все собирается. Можно делать те же мобильные приложения на обе платформы без необходимости покупать оверпрайс огрызок, который через 5 лет все равно выбрасывать, т.к. обнов он уже не получит, а на старую ось новые сдк не встанут
А на что свалили? Лично мне после них другими IDE пользоваться невозможно, все кажется тупым и неудобным. При этом с каждым годом в той же Идее все больше багов, но альтернативы еще хуже
Советую ощупать Jetbrains Toolbox. Официальная тулза для централизованной установки и обновления их продуктов. И да, там автообновление отключается, и сразу для всего, и индивидуально для каждой IDE
Из коробки exe/appimage, в котором внутри нужные классы для рантайма (и только они). Но руками прикручивается и фулл натив, просто больше архитектурных вопросов решать придется
"macOS apps built using .NET MAUI use Mac Catalyst, a solution from Apple that brings your iOS app built with UIKit to the desktop, and augments it with additional AppKit and platform APIs as required"
С той же статьи
В Джаве для этого есть Spring Data JDBC. Те же автоматическая десериализация, готовый круд, декларативные транзакции и тд, но запросы пишутся руками. Не отбирает контроль, облегчает жизнь
Но большинству макак слишком сложно, проще 100+ аннотаций для JPA навесить на энтити и потом месяц пытаться понять, почему все это работает не так, как ожидалось
Мне больше нравится подход SQLDelight с мультиплатформы Котлина и JOOQ из Джавы. Когда разработчик руками пишет SQL-запросы, а библиотека по ним и миграциям генерирует энтити и методы в репозиториях для вызова этих запросов. Получается "ORM наоборот", который и не отбирает контроль, и не генерирует всякую хрень (чем славится тот же Hibernate), и при этом облегчает работу
"We don't care which you choose, just don't choose an ORM" (c) Jake Wharton, Google & Alec Strong, Square, Inc.
Не могу ничего сказать, т.к. никогда не писал на шарпе в целом и Xamarin в частности.
НО: Xamarin в целом же заброшен, насколько до меня слухи доходили. Теперь будет MAUI, по любимой традиции шарпа постоянно бросать "революционные" технологии и заменять их "еще более революционными", чтобы потом забросить уже их. И работать он будет через Моно (везде, кроме винды), а на MacOS вообще через эмулятор ios. Т.е. никаким фулл нативом, возможностью юзать нативные либы платформ и тд даже не пахнет. Будет очередной React Native, но на шарпе
С учетом такого будущего сравнивать не вижу смысла)
В КМ приложение бьется на модули/sourceset-ы (иерархию разработчик выбирает сам), один из которых является кроссплатформерным, а остальные - для каждой платформы индивидуально.
Поддерживается множество платформ, включая WearOS, WatchOS и TVOS
Обычно всё, кроме UI, выносят в шейред/коммон модуль, а для каждой платформы делают UI отдельно. Но с недавним выходом Compose Multiplatform можно делать UI для Андроида и десктопа один раз, если хочется. В данный момент идет разработка (экспериментальный релиз доступен) Multiplatform Compose (не путать с Compose Multiplatform, его потом собираются вливать туда), который должен позволить писать UI под IOS точно так же, как под Android. С наличием Compose Multiplatform, позволяющим писать под Android и десктоп один раз, дублирование будет только в вебе
Т.е., если нам надо сделать приложение, работающее везде (десктоп, андроид, айос, веб), то это будет 1 общий модуль с бизнес-логикой, DI, логикой хранения данных и тд, и по 1 модулю для каждой из платформ, где будет UI для них
При этом зависимости каждого модуля мы выбираем самостоятельно. Например, при сборке под айос, код на Котлине превратится в библиотеку на Swift, что позволит разрабатывать UI на Swift тем, кто привык работать с айос, использовать их нативные библиотеки и тд. В вебе можно писать как на самом Котлине (его обертке вокруг Compose), для знакомых с разработкой на андроиде, так и на обертке на Котлине вокруг Реакта, так и на чистом нативном Реакте на жс/тс
Все это дает несколько плюсов и один минус
Минус:
Есть дублирование в виде UI-кода под разные платформы. Частично решается библиотеками, но все равно что-то на визуальной части будет дублироваться, что усложнит поддержку. В данный момент эту проблему как раз и решают, растаскивая Compose на все платформы, куда дотягиваются
Плюсы:
Полный натив. Никакого лишнего движка рендера, как в React Native или Flutter, никакого WebView, как в Ionic. На Андроиде будет фулл натив андроид приложение, на свифте - фулл натив свифт приложение, на десктопе - бинарник на жвм или фулл натив на выбор, в вебе - фулл натив жс.
Возможность не-кроссплатформерным разработчикам делать UI под каждую платформу без необходимости уметь в эту кроссплатформерную разработку. Например, в команде есть человек, знающий только свифт. Никто не мешает ему делать UI под айос на этом свифте для вашей кроссплатформы, как он привык и с какими угодно либами свифта (т.к. все, кроме UI, превращается просто в библиотеку)
Разработчик сам определяет зависимости каждого модуля. То есть можно спокойно использовать фулл нативные библиотеки каждой платформы только для нее, не полагаясь на наличие каких-то там нужных плагинов. Например, в вебе тот же реакт и библиотеки для него - сколько угодно. На андроиде библиотеки только для андроида - пожалуйста
Разработчик сам определяет еще и какой код нужно выносить на мультиплатформу, а какой оставить только для конкретной. Это делается с помощью иерархии модулей и связки expect/actual. Если хочется, никто не заставляет шарить все, кроме UI. Можно и больше кода вынести на конкретные платформы. Собственно, картинка выше это и отображает. Возможность задать иерархию какого угодно уровня
Пример связки expect/actual
Есть уже далеко не малое количество библиотек с поддержкой Kotlin Multiplatform, позволяющих 80-90% кода, включая UI, вынести в коммон/шейред модуль. Базы данных, веб-клиенты, DI, вьюмодели, реклама, безопасность, аналитика и прочее. Есть даже целый проект https://arkivanov.github.io/Decompose/, следующий парадигме pluggable ui для разделения кода
Отвечая на Ваши вопросы:
Столько же, сколько и нативное под эту платформу. Kotlin Multiplatform просто собирает модули в библиотеку и позволяет подключить ее при разработке UI, чтобы не писать все, кроме UI, заново.
Потребуется как минимум часть UI писать под каждую платформу отдельно. Остальное можно полностью вынести в кроссплатформу, если надо. Если не надо, можно не выносить или вынести часть
На нативных для каждой платформы. Андроид и WearOS - Java/Kotlin, Веб - Kotlin/JS и/или просто JS/TS, Ios/TVOS/WatchOS - Swift, Десктоп на жвм - Java/Kotlin. Это позволяет использовать нативные библиотеки и не задумываться, сделали уже нужный плагин или нет
Не совсем общий. Как минимум часть UI будет на разных языках (Kotlin/Swift). Поддержку требовать будут нативные фичи каждой платформы (которые Вы сами решаете, использовать или нет) и сам этот UI
Прикрепляю пару кроссплатформерных проектов для примера
https://github.com/joreilly/PeopleInSpace
Поддержка Android, IOS, WearOS, WatchOS, Desktop, Web с несколькими вариантами реализаций для разных платформ
https://github.com/mutualmobile/PraxisKMP
Поддержка Android, IOS, WearOS, WatchOS, Desktop, Web (React)
Итого, это не имеющая на данный момент аналогов технология (по крайней мере из того, что на слуху), позволяющая делать мультиплатформерные клиентские приложения с полным нативом и минимальным дублирование кода (а в перспективе и вообще без него), с сохранением полной свободы творчества и возможностей разработчика, при этом использующая максимально привычный и общепринятый инструментарий
Во-первых, UI для ios и android разный, т.е. все равно будет дублирование. Во-вторых, в последний раз, когда я смотрел, Flutter Desktop и Flutter Web были просто ужасны, это был просто тот же самый мобильный UI, просто растянутый на десктопный экран.
В третьих, я честно не знаю, зачем использовать Flutter со всеми его проблемами + локальным языком, когда есть тот же Kotlin Multiplatform, позволяющий то же, только с гораздо меньшими костылями, нативно и на более популярном и общепринятом языке
Вы использовали тупль, который тут хорошо подходит, да. Но если переменных больше 2? Если надо работать с переменными, которые по смысле не объединить в одну структуру?
Вы говорите про synchronized, который синхронизирует по объекту. А я говорю про реализации интерфейса Lock из пакета java.util.concurrent.locks. Например ReentrantLock
Вот пример с аналогичным для Сишных мьютексов кодом на Джаве
Возникает интересный вопрос: а если нам надо свопнуть два значения с помощью мьютексов, как это нормально реализовать в Расте? Ну то есть через мьютексы в Си или локи в Жаве можно просто объявить кусок кода однопоточным и сделать там, что угодно
Но в расте, получается, придется делать по мьютексу на каждую используемую переменную. А если это не своп и их не 2, а больше? Оптимизационная проблема получается
С этим языком знаком плохо, поэтому буду рад, если подскажете, как это можно сделать лучше
Но на данный момент ничего лучше следующего не приходит на ум, а это не очень:
Я чуть ниже запостил код, если что-то еще понадобится - обращайтесь)
То есть, код следующего вида:
Превращается в такой вот эндпоинт:
При использовании этого решения натыкался на проблему: при наличии в контроллере более одного маппинга на один и тот же адрес, но с разными параметрами, в Сваггере в итоге все эти маппинги превращались в один эндпоинт, описание, схема и прочее которого случайно бралось от одного из маппингов, а в параметрах были абсолютно все параметры из всех маппингов по этому адресу, и с пометкой required (даже если в самих маппингах явно стоит required = false)
Судя по всему, он просто мержит все эндпоинты на основании их адреса, а не методов с маппингами. В итоге вместо нескольких нормальных маппингов получается один, в который навалено все подряд в случайном порядке, да еще и вводящие в заблуждение параметры указаны
Есть ли какой-то способ это починить?
Когда винду переустановите на линукс)
Слез с винды года 4 назад, полет нормальный. Играть или работать секретаршей не так удобно, зато для разработки и остальных нужд - золото. При этом, если мння что-то не устраивает в системе, я могу это изменить
а если нужны специфические фичи винды или мака, я просто делаю виртуалку и пробрасываю туда железо (чего ни винда, ни мак не умеют). Только недавно Big Sur поставил и обновил до Monterey в виртуалке, XCode работает, все собирается. Можно делать те же мобильные приложения на обе платформы без необходимости покупать оверпрайс огрызок, который через 5 лет все равно выбрасывать, т.к. обнов он уже не получит, а на старую ось новые сдк не встанут
Фикс дров нвидии в убунте = 2 строки в терминале
Каким боком дизайн браузера относится к линуксу?)
Если вы такой везучий, что кеды сломали, то используйте гном. Или i3. Или xfce. Или еще что угодно. У вас есть выбор и руки, в отличие от жертв винды
И каждый раз оно на ней чинится ровно двумя строчками, в отличие от того же дебиана. Проходили уже
А на что свалили? Лично мне после них другими IDE пользоваться невозможно, все кажется тупым и неудобным. При этом с каждым годом в той же Идее все больше багов, но альтернативы еще хуже
Советую ощупать Jetbrains Toolbox. Официальная тулза для централизованной установки и обновления их продуктов. И да, там автообновление отключается, и сразу для всего, и индивидуально для каждой IDE