some fix, add use libass feature

This commit is contained in:
kodjomoustapha 2024-07-10 10:18:54 +01:00
parent c25bf014c6
commit 98612f3511
73 changed files with 253 additions and 4523 deletions

BIN
assets/fonts/subfont.ttf Normal file

Binary file not shown.

View file

@ -323,5 +323,8 @@
"grid_size": "Grid size",
"n_per_row": "{n} per row",
"horizontal_continious": "Horizontal continuous",
"edit_code": "Edit code"
"edit_code": "Edit code",
"use_libass": "Enable libass",
"use_libass_info": "Use libass based subtitle rendering for native backend.",
"libass_not_disable_message": "Disable `use libass` in player settings to be able to customize the subtitles."
}

View file

@ -186,6 +186,8 @@ class Settings {
@enumerated
late SectionType disableSectionType;
bool? useLibass;
Settings(
{this.id = 227,
this.displayType = DisplayType.compactGrid,
@ -267,7 +269,8 @@ class Settings {
this.appFontFamily,
this.mangaGridSize,
this.animeGridSize,
this.disableSectionType = SectionType.all});
this.disableSectionType = SectionType.all,
this.useLibass = true});
Settings.fromJson(Map<String, dynamic> json) {
animatePageTransitions = json['animatePageTransitions'];
@ -416,6 +419,7 @@ class Settings {
animeGridSize = json['animeGridSize'];
disableSectionType =
SectionType.values[json['disableSectionType'] ?? SectionType.all];
useLibass = json['useLibass'];
}
Map<String, dynamic> toJson() => {
@ -523,7 +527,8 @@ class Settings {
'appFontFamily': appFontFamily,
'mangaGridSize': mangaGridSize,
'animeGridSize': animeGridSize,
'disableSectionType': disableSectionType.index
'disableSectionType': disableSectionType.index,
'useLibass': useLibass
};
}

View file

@ -451,13 +451,18 @@ const SettingsSchema = CollectionSchema(
name: r'updateProgressAfterReading',
type: IsarType.bool,
),
r'usePageTapZones': PropertySchema(
r'useLibass': PropertySchema(
id: 82,
name: r'useLibass',
type: IsarType.bool,
),
r'usePageTapZones': PropertySchema(
id: 83,
name: r'usePageTapZones',
type: IsarType.bool,
),
r'userAgent': PropertySchema(
id: 83,
id: 84,
name: r'userAgent',
type: IsarType.string,
)
@ -911,8 +916,9 @@ void _settingsSerialize(
writer.writeLong(offsets[79], object.startDatebackup);
writer.writeBool(offsets[80], object.themeIsDark);
writer.writeBool(offsets[81], object.updateProgressAfterReading);
writer.writeBool(offsets[82], object.usePageTapZones);
writer.writeString(offsets[83], object.userAgent);
writer.writeBool(offsets[82], object.useLibass);
writer.writeBool(offsets[83], object.usePageTapZones);
writer.writeString(offsets[84], object.userAgent);
}
Settings _settingsDeserialize(
@ -1073,8 +1079,9 @@ Settings _settingsDeserialize(
startDatebackup: reader.readLongOrNull(offsets[79]),
themeIsDark: reader.readBoolOrNull(offsets[80]),
updateProgressAfterReading: reader.readBoolOrNull(offsets[81]),
usePageTapZones: reader.readBoolOrNull(offsets[82]),
userAgent: reader.readStringOrNull(offsets[83]),
useLibass: reader.readBoolOrNull(offsets[82]),
usePageTapZones: reader.readBoolOrNull(offsets[83]),
userAgent: reader.readStringOrNull(offsets[84]),
);
object.chapterFilterBookmarkedList =
reader.readObjectList<ChapterFilterBookmarked>(
@ -1366,6 +1373,8 @@ P _settingsDeserializeProp<P>(
case 82:
return (reader.readBoolOrNull(offset)) as P;
case 83:
return (reader.readBoolOrNull(offset)) as P;
case 84:
return (reader.readStringOrNull(offset)) as P;
default:
throw IsarError('Unknown property with id $propertyId');
@ -6805,6 +6814,32 @@ extension SettingsQueryFilter
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> useLibassIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
property: r'useLibass',
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> useLibassIsNotNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNotNull(
property: r'useLibass',
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> useLibassEqualTo(
bool? value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'useLibass',
value: value,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition>
usePageTapZonesIsNull() {
return QueryBuilder.apply(this, (query) {
@ -8008,6 +8043,18 @@ extension SettingsQuerySortBy on QueryBuilder<Settings, Settings, QSortBy> {
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> sortByUseLibass() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'useLibass', Sort.asc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> sortByUseLibassDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'useLibass', Sort.desc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> sortByUsePageTapZones() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'usePageTapZones', Sort.asc);
@ -8896,6 +8943,18 @@ extension SettingsQuerySortThenBy
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> thenByUseLibass() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'useLibass', Sort.asc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> thenByUseLibassDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'useLibass', Sort.desc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> thenByUsePageTapZones() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'usePageTapZones', Sort.asc);
@ -9358,6 +9417,12 @@ extension SettingsQueryWhereDistinct
});
}
QueryBuilder<Settings, Settings, QDistinct> distinctByUseLibass() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'useLibass');
});
}
QueryBuilder<Settings, Settings, QDistinct> distinctByUsePageTapZones() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'usePageTapZones');
@ -9928,6 +9993,12 @@ extension SettingsQueryProperty
});
}
QueryBuilder<Settings, bool?, QQueryOperations> useLibassProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'useLibass');
});
}
QueryBuilder<Settings, bool?, QQueryOperations> usePageTapZonesProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'usePageTapZones');

View file

@ -26,7 +26,10 @@ import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
import 'package:media_kit/media_kit.dart';
import 'package:media_kit_video/media_kit_video.dart';
import 'package:media_kit_video/media_kit_video_controls/src/controls/extensions/duration.dart';
import 'package:path_provider/path_provider.dart';
import 'package:window_manager/window_manager.dart';
// ignore: depend_on_referenced_packages
import 'package:path/path.dart' as path;
class AnimePlayerView extends riv.ConsumerStatefulWidget {
final Chapter episode;
@ -40,7 +43,9 @@ class _AnimePlayerViewState extends riv.ConsumerState<AnimePlayerView> {
String? _infoHash;
@override
void dispose() {
MTorrentServer().removeTorrent(_infoHash);
if (_infoHash != null) {
MTorrentServer().removeTorrent(_infoHash);
}
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
overlays: SystemUiOverlay.values);
super.dispose();
@ -53,8 +58,9 @@ class _AnimePlayerViewState extends riv.ConsumerState<AnimePlayerView> {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
return serversData.when(
data: (data) {
_infoHash = data.$3;
if (data.$1.isEmpty &&
final (videos, isLocal, infoHash) = data;
_infoHash = infoHash;
if (videos.isEmpty &&
!(widget.episode.manga.value!.isLocalArchive ?? false)) {
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
@ -67,15 +73,15 @@ class _AnimePlayerViewState extends riv.ConsumerState<AnimePlayerView> {
),
),
body: const Center(
child: Text("Error"),
child: Text("Video list is empty"),
),
);
}
return AnimeStreamPage(
episode: widget.episode,
videos: data.$1,
isLocal: data.$2,
videos: videos,
isLocal: isLocal,
);
},
error: (error, stackTrace) => Scaffold(
@ -133,19 +139,18 @@ class AnimeStreamPage extends riv.ConsumerStatefulWidget {
class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
with TickerProviderStateMixin {
late final GlobalKey<VideoState> _key = GlobalKey<VideoState>();
late final Player _player = Player();
late final useLibass = ref.read(useLibassStateProvider);
late final Player _player =
Player(configuration: PlayerConfiguration(libass: useLibass));
late final VideoController _controller = VideoController(_player);
late final _streamController =
ref.read(animeStreamControllerProvider(episode: widget.episode).notifier);
late final _firstVid = widget.videos.first;
late final ValueNotifier<VideoPrefs?> _video = ValueNotifier(VideoPrefs(
videoTrack: VideoTrack(
_firstVid.originalUrl, _firstVid.quality, _firstVid.quality),
headers: _firstVid.headers));
final ValueNotifier<double> _playbackSpeed = ValueNotifier(1.0);
bool _initSubtitleAndAudio = true;
final ValueNotifier<bool> _enterFullScreen = ValueNotifier(false);
late final ValueNotifier<Duration> _currentPosition =
ValueNotifier(_streamController.geTCurrentPosition());
@ -154,6 +159,13 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
final ValueNotifier<bool> _isCompleted = ValueNotifier(false);
final ValueNotifier<Duration?> _tempPosition = ValueNotifier(null);
final ValueNotifier<BoxFit> _fit = ValueNotifier(BoxFit.contain);
final ValueNotifier<bool> _showAniSkipOpeningButton = ValueNotifier(false);
final ValueNotifier<bool> _showAniSkipEndingButton = ValueNotifier(false);
Results? _openingResult;
Results? _endingResult;
bool _hasOpeningSkip = false;
bool _hasEndingSkip = false;
bool _initSubtitleAndAudio = true;
late final StreamSubscription<Duration> _currentPositionSub =
_player.stream.position.listen(
@ -163,27 +175,25 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
10;
_currentPosition.value = position;
if ((_firstVid.subtitles ?? []).isNotEmpty) {
if (_firstVid.subtitles?.isNotEmpty ?? false) {
if (_initSubtitleAndAudio) {
try {
if (_firstVid.subtitles?.isNotEmpty ?? false) {
final file = _firstVid.subtitles?.first.file ?? "";
final label = _firstVid.subtitles?.first.label;
_player.setSubtitleTrack(file.startsWith("http")
? SubtitleTrack.uri(file, title: label, language: label)
: SubtitleTrack.data(file, title: label, language: label));
}
final file = _firstVid.subtitles!.first.file ?? "";
final label = _firstVid.subtitles!.first.label;
_player.setSubtitleTrack(file.startsWith("http")
? SubtitleTrack.uri(file, title: label, language: label)
: SubtitleTrack.data(file, title: label, language: label));
} catch (_) {}
try {
if (_firstVid.audios?.isNotEmpty ?? false) {
_player.setAudioTrack(AudioTrack.uri(
_firstVid.audios?.first.file ?? "",
title: _firstVid.audios?.first.label,
language: _firstVid.audios?.first.label));
}
} catch (_) {}
_initSubtitleAndAudio = false;
}
try {
if (_firstVid.audios?.isNotEmpty ?? false) {
_player.setAudioTrack(AudioTrack.uri(
_firstVid.audios!.first.file ?? "",
title: _firstVid.audios!.first.label,
language: _firstVid.audios!.first.label));
}
} catch (_) {}
_initSubtitleAndAudio = false;
}
},
);
@ -194,6 +204,7 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
_currentTotalDuration.value = duration;
},
);
late final StreamSubscription<bool> _completed =
_player.stream.completed.listen(
(val) async {
@ -213,33 +224,48 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
}
},
);
Results? _openingResult;
Results? _endingResult;
bool _hasOpeningSkip = false;
bool _hasEndingSkip = false;
final ValueNotifier<bool> _showAniSkipOpeningButton = ValueNotifier(false);
final ValueNotifier<bool> _showAniSkipEndingButton = ValueNotifier(false);
@override
void initState() {
_setCurrentPosition(true);
_seekToCurrentPosition();
_seekToOrCurrentPosition();
_currentPositionSub;
_currentTotalDurationSub;
_completed;
_player.open(Media(_video.value!.videoTrack!.id,
httpHeaders: _video.value!.headers));
_setPlaybackSpeed(ref.read(defaultPlayBackSpeedStateProvider));
_initAniSkip();
_loadAndroidFont().then(
(_) {
_player.open(Media(_video.value!.videoTrack!.id,
httpHeaders: _video.value!.headers));
_setPlaybackSpeed(ref.read(defaultPlayBackSpeedStateProvider));
_initAniSkip();
},
);
super.initState();
}
void _seekToCurrentPosition({Duration? duration}) async {
await Future.doWhile(() async {
Future<void> _loadAndroidFont() async {
if (Platform.isAndroid && useLibass) {
try {
final subDir = await getApplicationDocumentsDirectory();
final fontPath = path.join(subDir.path, 'subfont.ttf');
final data = await rootBundle.load('assets/fonts/subfont.ttf');
final bytes =
data.buffer.asInt8List(data.offsetInBytes, data.lengthInBytes);
final fontFile = await File(fontPath).create(recursive: true);
await fontFile.writeAsBytes(bytes);
await (_player.platform as NativePlayer)
.setProperty('sub-fonts-dir', subDir.path);
await (_player.platform as NativePlayer)
.setProperty('sub-font', 'Droid Sans Fallback');
} catch (_) {}
}
}
void _seekToOrCurrentPosition({Duration? duration}) async {
if (duration == null) {
await Future.delayed(const Duration(milliseconds: 300));
await _player.stream.buffer.first;
_player.seek(duration ?? _streamController.geTCurrentPosition());
return false;
});
}
await _player.stream.buffer.first;
_player.seek(duration ?? _streamController.geTCurrentPosition());
}
void _initAniSkip() async {
@ -276,7 +302,6 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
} else {
_setLandscapeMode(false);
}
super.dispose();
}
@ -346,7 +371,7 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
child: textWidget(
widget.isLocal ? _firstVid.quality : quality.videoTrack!.title!,
selected),
onTap: () {
onTap: () async {
_video.value = quality;
if (quality.isLocal) {
if (widget.isLocal) {
@ -359,7 +384,7 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
_player.open(Media(quality.videoTrack!.id,
httpHeaders: quality.headers));
}
_seekToCurrentPosition(duration: _currentPosition.value);
_seekToOrCurrentPosition(duration: _currentPosition.value);
Navigator.pop(context);
},
);
@ -388,15 +413,25 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
fullWidth: true,
moreWidget: IconButton(
onPressed: () async {
await customDraggableTabBar(tabs: [
Tab(text: l10n.font),
Tab(text: l10n.color),
], children: [
FontSettingWidget(hasSubtitleTrack: hasSubtitleTrack),
ColorSettingWidget(hasSubtitleTrack: hasSubtitleTrack)
], context: context, vsync: this, fullWidth: true);
if (context.mounted) {
Navigator.pop(context);
if (useLibass) {
BotToast.showText(
contentColor: Colors.white,
textStyle: const TextStyle(color: Colors.black, fontSize: 20),
onlyOne: true,
align: const Alignment(0, 0.90),
duration: const Duration(seconds: 2),
text: context.l10n.libass_not_disable_message);
} else {
await customDraggableTabBar(tabs: [
Tab(text: l10n.font),
Tab(text: l10n.color),
], children: [
FontSettingWidget(hasSubtitleTrack: hasSubtitleTrack),
ColorSettingWidget(hasSubtitleTrack: hasSubtitleTrack)
], context: context, vsync: this, fullWidth: true);
if (context.mounted) {
Navigator.pop(context);
}
}
},
icon: const Icon(Icons.settings_outlined)),

View file

@ -8,6 +8,7 @@ import 'package:mangayomi/modules/anime/anime_player_view.dart';
import 'package:mangayomi/modules/anime/providers/anime_player_controller_provider.dart';
import 'package:mangayomi/modules/anime/widgets/custom_seekbar.dart';
import 'package:mangayomi/modules/anime/widgets/subtitle_view.dart';
import 'package:mangayomi/modules/more/settings/player/providers/player_state_provider.dart';
import 'package:media_kit_video/media_kit_video.dart';
import 'package:media_kit_video/media_kit_video_controls/src/controls/extensions/duration.dart';
import 'package:window_manager/window_manager.dart';
@ -192,12 +193,14 @@ class _DesktopControllerWidgetState extends State<DesktopControllerWidget> {
child: Stack(
children: [
Consumer(
builder: (context, ref, _) => Positioned(
child: CustomSubtitleView(
controller: widget.videoController,
configuration:
SubtitleViewConfiguration(style: subtileTextStyle(ref)),
)),
builder: (context, ref, _) => ref.read(useLibassStateProvider)
? const SizedBox.shrink()
: Positioned(
child: CustomSubtitleView(
controller: widget.videoController,
configuration:
SubtitleViewConfiguration(style: subtileTextStyle(ref)),
)),
),
Focus(
autofocus: true,
@ -815,26 +818,15 @@ Future<bool> setFullScreen({bool? value}) async {
if (value != null) {
final isFullScreen = await windowManager.isFullScreen();
if (value != isFullScreen) {
await windowManager.setTitleBarStyle(
value == false ? TitleBarStyle.normal : TitleBarStyle.hidden);
await windowManager.setFullScreen(value);
if (value == false) {
await windowManager.center();
}
await windowManager.show();
}
return value;
}
final isFullScreen = await windowManager.isFullScreen();
if (!isFullScreen) {
await windowManager.setTitleBarStyle(TitleBarStyle.hidden);
await windowManager.setFullScreen(true);
await windowManager.show();
} else {
await windowManager.setTitleBarStyle(TitleBarStyle.normal);
await windowManager.setFullScreen(false);
await windowManager.center();
await windowManager.show();
}
return isFullScreen;
}

View file

@ -289,12 +289,14 @@ class _MobileControllerWidgetState
return Stack(
children: [
Consumer(
builder: (context, ref, _) => Positioned(
child: CustomSubtitleView(
controller: widget.videoController,
configuration:
SubtitleViewConfiguration(style: subtileTextStyle(ref)),
)),
builder: (context, ref, _) => ref.read(useLibassStateProvider)
? const SizedBox.shrink()
: Positioned(
child: CustomSubtitleView(
controller: widget.videoController,
configuration:
SubtitleViewConfiguration(style: subtileTextStyle(ref)),
)),
),
Focus(
autofocus: true,

View file

@ -18,6 +18,8 @@ import 'package:path_provider/path_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'download_provider.g.dart';
FileDownloader _mangaFileDownloader = FileDownloader(isAnime: false);
FileDownloader _animeFileDownloader = FileDownloader(isAnime: true);
@riverpod
Future<List<String>> downloadChapter(
DownloadChapterRef ref, {
@ -232,9 +234,8 @@ Future<List<String>> downloadChapter(
isar.downloads.putSync(download..chapter.value = chapter);
});
} else {
savePageUrls();
if (isManga) {
await FileDownloader(isAnime: false).downloadBatch(
await _mangaFileDownloader.downloadBatch(
tasks,
batchProgressCallback: (succeeded, failed) async {
if (succeeded == tasks.length) {
@ -287,7 +288,7 @@ Future<List<String>> downloadChapter(
},
);
} else {
await FileDownloader(isAnime: true).download(
await _animeFileDownloader.download(
tasks.first,
onProgress: (progress) async {
bool isEmpty = isar.downloads

View file

@ -6,7 +6,7 @@ part of 'download_provider.dart';
// RiverpodGenerator
// **************************************************************************
String _$downloadChapterHash() => r'de1315d4bfaf41676c567c07d1e0ed816b7d569e';
String _$downloadChapterHash() => r'55ee5ac033e4616be7fbf040a7396a2f9d36599d';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -6,7 +6,7 @@ part of 'crop_borders_provider.dart';
// RiverpodGenerator
// **************************************************************************
String _$cropBordersHash() => r'2f295179ecab0d811728451a2dbc8c61121f50e3';
String _$cropBordersHash() => r'857ae4319c11ee55cbaa2ae15b57bda240329c0d';
/// Copied from Dart SDK
class _SystemHash {

View file

@ -13,15 +13,13 @@ class PlayerScreen extends ConsumerWidget {
final markEpisodeAsSeenType = ref.watch(markEpisodeAsSeenTypeStateProvider);
final defaultSkipIntroLength =
ref.watch(defaultSkipIntroLengthStateProvider);
final defaultDoubleTapToSkipLength =
ref.watch(defaultDoubleTapToSkipLengthStateProvider);
final defaultPlayBackSpeed = ref.watch(defaultPlayBackSpeedStateProvider);
final enableAniSkip = ref.watch(enableAniSkipStateProvider);
final enableAutoSkip = ref.watch(enableAutoSkipStateProvider);
final aniSkipTimeoutLength = ref.watch(aniSkipTimeoutLengthStateProvider);
final useLibass = ref.watch(useLibassStateProvider);
return Scaffold(
appBar: AppBar(
title: Text(context.l10n.player),
@ -285,9 +283,17 @@ class PlayerScreen extends ConsumerWidget {
style:
TextStyle(fontSize: 11, color: context.secondaryColor)),
),
SwitchListTile(
value: useLibass,
title: Text(context.l10n.use_libass),
subtitle: Text(context.l10n.use_libass_info,
style:
TextStyle(fontSize: 11, color: context.secondaryColor)),
onChanged: (value) {
ref.read(useLibassStateProvider.notifier).set(value);
}),
ExpansionTile(
title: Text(context.l10n.enable_aniskip),
shape: const StarBorder(),
initiallyExpanded: enableAniSkip,
trailing: IgnorePointer(
child: Switch(

View file

@ -108,3 +108,18 @@ class AniSkipTimeoutLengthState extends _$AniSkipTimeoutLengthState {
() => isar.settings.putSync(settings!..aniSkipTimeoutLength = value));
}
}
@riverpod
class UseLibassState extends _$UseLibassState {
@override
bool build() {
return isar.settings.getSync(227)!.useLibass ?? true;
}
void set(bool value) {
final settings = isar.settings.getSync(227);
state = value;
isar.writeTxnSync(
() => isar.settings.putSync(settings!..useLibass = value));
}
}

View file

@ -125,5 +125,21 @@ final aniSkipTimeoutLengthStateProvider =
);
typedef _$AniSkipTimeoutLengthState = AutoDisposeNotifier<int>;
String _$useLibassStateHash() => r'09c661f72c8777f360f48f2203d767b9caf6e4e7';
/// See also [UseLibassState].
@ProviderFor(UseLibassState)
final useLibassStateProvider =
AutoDisposeNotifierProvider<UseLibassState, bool>.internal(
UseLibassState.new,
name: r'useLibassStateProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$useLibassStateHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$UseLibassState = AutoDisposeNotifier<bool>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View file

@ -1,83 +0,0 @@
## 0.2.3
* fix macOS webview window size not working.
## 0.2.2
* fix memory leak on macOS after close webview window.
* Show and Hide Webview window by [@Iri-Hor](https://github.com/Iri-Hor) in [#268](https://github.com/MixinNetwork/flutter-plugins/pull/268)
## 0.2.1
* add Windows attentions to readme.
* fix linux close sub window cause app exited.
* fix linux webview title bar expanded unexpected.
* More control over webview position and size under windows. [#206](https://github.com/MixinNetwork/flutter-plugins/pull/206) by [Lukas Heinze](https://github.com/Iri-Hor)
* fix zone mismatch [#250](https://github.com/MixinNetwork/flutter-plugins/pull/250) by [CD](https://github.com/459217974)
* fix linux webkit2gtk deprecated error [#246](https://github.com/MixinNetwork/flutter-plugins/pull/246) by [Zhiqiang Zhang](https://github.com/zhangzqs)
## 0.2.0
* BREAK CHANGE: bump linux webkit2gtk version to 4.1
## 0.1.6
* fix WebView render area wrong offset on Windows.
## 0.1.5
* add `close` method for WebView.
* add `onUrlRequest` event for WebView.
## 0.1.4
* support custom userDataFolder on Windows.
* fix open web view failed cause crash on Windows.
## 0.1.3
Remove windows addition import requirements.
## 0.1.2
fix TitleBar reload do not work.
## 0.1.1
fix window title not show on macOS
## 0.1.0
support custom titlebar.
NOTE: contains break change. more details see readme.
## 0.0.7
1. support `isWebviewAvailable` check.
2. fix `clearAll` crash on Linux if no webview created.
## 0.0.6
fix swift definition conflict on macOS. [flutter-plugins#17](https://github.com/MixinNetwork/flutter-plugins/issues/17)
## 0.0.5
add `setApplicationNameForUserAgent` for append application name to webview user agent.
## 0.0.4
1. implement `addScriptToExecuteOnDocumentCreated` on macOS.
2. add hot key `command + w` to close window.
## 0.0.3
fix linux build
## 0.0.2
* rename project to desktop_webview_window
## 0.0.1
* add Windows, Linux, macOS support.

View file

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [2021] [Mixin]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -1,77 +0,0 @@
# desktop_webview_window
[![Pub](https://img.shields.io/pub/v/desktop_webview_window.svg)](https://pub.dev/packages/desktop_webview_window)
Show a webview window on your flutter desktop application.
| | | |
| -------- | ------- | ---- |
| Windows | ✅ | [Webview2](https://www.nuget.org/packages/Microsoft.Web.WebView2) 1.0.992.28 |
| Linux | ✅ | [WebKitGTK-4.1](https://webkitgtk.org/reference/webkit2gtk/stable/index.html) |
| macOS | ✅ | WKWebview |
## Getting Started
1. modify your `main` method.
```dart
import 'package:desktop_webview_window/desktop_webview_window.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Add this your main method.
// used to show a webview title bar.
if (runWebViewTitleBarWidget(args)) {
return;
}
runApp(MyApp());
}
```
2. launch WebViewWindow
```dart
final webview = await WebviewWindow.create();
webview.launch("https://example.com");
```
## linux requirement
```shell
sudo apt-get install webkit2gtk-4.1
```
## Windows
### Requirement
The backend of desktop_webview_window on Windows is WebView2, which requires **WebView2 Runtime** installed.
[WebView2 Runtime](https://developer.microsoft.com/en-us/microsoft-edge/webview2) is ship in box with Windows11, but
it may not installed on Windows10 devices. So you need consider how to distribute the runtime to your users.
See more: https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution
For convenience, you can use `WebviewWindow.isWebviewAvailable()` check whether the WebView2 is available.
### Attention
The default user data folder of WebView2 is `your_exe_file\WebView2`, which is not a good place to store user data.
eg. if the application is installed in a read-only directory, the application will crash when WebView2 try to write data.
you can use `WebviewWindow.create()` to create a webview with a custom user data folder.
```dart
final webview = await WebviewWindow.create(
confiruation: CreateConfiguration(
userDataFolderWindows: 'your_custom_user_data_folder',
),
);
```
## License
see [LICENSE](./LICENSE)

View file

@ -1,4 +0,0 @@
include: package:flutter_lints/flutter.yaml
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

View file

@ -1,16 +0,0 @@
# webview_window_example
Demonstrates how to use the webview_window plugin.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
For help getting started with Flutter, view our
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

View file

@ -1,29 +0,0 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

View file

@ -1,184 +0,0 @@
import 'dart:io';
import 'package:desktop_webview_window/desktop_webview_window.dart';
import 'package:flutter/material.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
void main(List<String> args) {
debugPrint('args: $args');
if (runWebViewTitleBarWidget(args)) {
return;
}
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final TextEditingController _controller = TextEditingController(
text: 'https://example.com',
);
bool? _webviewAvailable;
@override
void initState() {
super.initState();
WebviewWindow.isWebviewAvailable().then((value) {
setState(() {
_webviewAvailable = value;
});
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
actions: [
IconButton(
onPressed: () async {
final webview = await WebviewWindow.create(
configuration: CreateConfiguration(
windowHeight: 1280,
windowWidth: 720,
title: "ExampleTestWindow",
titleBarTopPadding: Platform.isMacOS ? 20 : 0,
userDataFolderWindows: await _getWebViewPath(),
),
);
webview
..registerJavaScriptMessageHandler("test", (name, body) {
debugPrint('on javaScipt message: $name $body');
})
..setApplicationNameForUserAgent(" WebviewExample/1.0.0")
..setPromptHandler((prompt, defaultText) {
if (prompt == "test") {
return "Hello World!";
} else if (prompt == "init") {
return "initial prompt";
}
return "";
})
..addScriptToExecuteOnDocumentCreated("""
const mixinContext = {
platform: 'Desktop',
conversation_id: 'conversationId',
immersive: false,
app_version: '1.0.0',
appearance: 'dark',
}
window.MixinContext = {
getContext: function() {
return JSON.stringify(mixinContext)
}
}
""")
..launch("http://localhost:3000/test.html");
},
icon: const Icon(Icons.bug_report),
)
],
),
body: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextField(controller: _controller),
const SizedBox(height: 16),
TextButton(
onPressed: _webviewAvailable != true ? null : _onTap,
child: const Text('Open'),
),
const SizedBox(height: 20),
TextButton(
onPressed: () async {
await WebviewWindow.clearAll(
userDataFolderWindows: await _getWebViewPath(),
);
debugPrint('clear complete');
},
child: const Text('Clear all'),
)
],
),
),
),
),
);
}
void _onTap() async {
final webview = await WebviewWindow.create(
configuration: CreateConfiguration(
userDataFolderWindows: await _getWebViewPath(),
titleBarTopPadding: Platform.isMacOS ? 20 : 0,
),
);
webview
..setBrightness(Brightness.dark)
..setApplicationNameForUserAgent(" WebviewExample/1.0.0")
..launch(_controller.text)
..addOnUrlRequestCallback((url) {
debugPrint('url: $url');
final uri = Uri.parse(url);
if (uri.path == '/login_success') {
debugPrint('login success. token: ${uri.queryParameters['token']}');
webview.close();
}
})
..onClose.whenComplete(() {
debugPrint("on close");
});
await Future.delayed(const Duration(seconds: 2));
for (final javaScript in _javaScriptToEval) {
try {
final ret = await webview.evaluateJavaScript(javaScript);
debugPrint('evaluateJavaScript: $ret');
} catch (e) {
debugPrint('evaluateJavaScript error: $e \n $javaScript');
}
}
}
}
const _javaScriptToEval = [
"""
function test() {
return;
}
test();
""",
'eval({"name": "test", "user_agent": navigator.userAgent})',
'1 + 1',
'undefined',
'1.0 + 1.0',
'"test"',
];
Future<String> _getWebViewPath() async {
final document = await getApplicationDocumentsDirectory();
return p.join(
document.path,
'desktop_webview_window',
);
}

View file

@ -1,2 +0,0 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"

View file

@ -1,2 +0,0 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig"

View file

@ -1,14 +0,0 @@
//
// Generated file. Do not edit.
//
import FlutterMacOS
import Foundation
import desktop_webview_window
import path_provider_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
DesktopWebviewWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWebviewWindowPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
}

View file

@ -1,11 +0,0 @@
// This is a generated file; do not edit or check into version control.
FLUTTER_ROOT=C:\flutter
FLUTTER_APPLICATION_PATH=C:\DEV\flutter\mangayomi\packages\desktop_webview_window\example
COCOAPODS_PARALLEL_CODE_SIGN=true
FLUTTER_BUILD_DIR=build
FLUTTER_BUILD_NAME=1.0.0
FLUTTER_BUILD_NUMBER=1
DART_OBFUSCATION=false
TRACK_WIDGET_CREATION=true
TREE_SHAKE_ICONS=false
PACKAGE_CONFIG=.dart_tool/package_config.json

View file

@ -1,12 +0,0 @@
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=C:\flutter"
export "FLUTTER_APPLICATION_PATH=C:\DEV\flutter\mangayomi\packages\desktop_webview_window\example"
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_BUILD_DIR=build"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=true"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=.dart_tool/package_config.json"

View file

@ -1,40 +0,0 @@
platform :osx, '10.12'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_macos_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_macos_build_settings(target)
end
end

View file

@ -1,28 +0,0 @@
PODS:
- desktop_webview_window (0.0.1):
- FlutterMacOS
- FlutterMacOS (1.0.0)
- path_provider_macos (0.0.1):
- FlutterMacOS
DEPENDENCIES:
- desktop_webview_window (from `Flutter/ephemeral/.symlinks/plugins/desktop_webview_window/macos`)
- FlutterMacOS (from `Flutter/ephemeral`)
- path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`)
EXTERNAL SOURCES:
desktop_webview_window:
:path: Flutter/ephemeral/.symlinks/plugins/desktop_webview_window/macos
FlutterMacOS:
:path: Flutter/ephemeral
path_provider_macos:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos
SPEC CHECKSUMS:
desktop_webview_window: d4365e71bcd4e1aa0c14cf0377aa24db0c16a7e2
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
path_provider_macos: 3c0c3b4b0d4a76d2bf989a913c2de869c5641a19
PODFILE CHECKSUM: c7161fcf45d4fd9025dc0f48a76d6e64e52f8176
COCOAPODS: 1.12.1

View file

@ -1,635 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXAggregateTarget section */
33CC111A2044C6BA0003C045 /* Flutter Assemble */ = {
isa = PBXAggregateTarget;
buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */;
buildPhases = (
33CC111E2044C6BF0003C045 /* ShellScript */,
);
dependencies = (
);
name = "Flutter Assemble";
productName = FLX;
};
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
127EA8516D3B0432D8A2C324 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6B451012A2EB682A5199F610 /* Pods_Runner.framework */; };
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 33CC111A2044C6BA0003C045;
remoteInfo = FLX;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
33CC110E2044A8840003C045 /* Bundle Framework */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Bundle Framework";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
2DA652A6747DAACB460CA29B /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
33CC10ED2044A3C60003C045 /* webview_window_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = webview_window_example.app; sourceTree = BUILT_PRODUCTS_DIR; };
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = "<group>"; };
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; };
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = "<group>"; };
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = "<group>"; };
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = "<group>"; };
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
487BD0E504B87804F9B4770E /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
60E196C41ABF89028378EB94 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
6B451012A2EB682A5199F610 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
33CC10EA2044A3C60003C045 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
127EA8516D3B0432D8A2C324 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
0FC36F805FF9C8AF745F5250 /* Pods */ = {
isa = PBXGroup;
children = (
60E196C41ABF89028378EB94 /* Pods-Runner.debug.xcconfig */,
2DA652A6747DAACB460CA29B /* Pods-Runner.release.xcconfig */,
487BD0E504B87804F9B4770E /* Pods-Runner.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
33BA886A226E78AF003329D5 /* Configs */ = {
isa = PBXGroup;
children = (
33E5194F232828860026EE4D /* AppInfo.xcconfig */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
333000ED22D3DE5D00554162 /* Warnings.xcconfig */,
);
path = Configs;
sourceTree = "<group>";
};
33CC10E42044A3C60003C045 = {
isa = PBXGroup;
children = (
33FAB671232836740065AC1E /* Runner */,
33CEB47122A05771004F2AC0 /* Flutter */,
33CC10EE2044A3C60003C045 /* Products */,
D73912EC22F37F3D000D13A0 /* Frameworks */,
0FC36F805FF9C8AF745F5250 /* Pods */,
);
sourceTree = "<group>";
};
33CC10EE2044A3C60003C045 /* Products */ = {
isa = PBXGroup;
children = (
33CC10ED2044A3C60003C045 /* webview_window_example.app */,
);
name = Products;
sourceTree = "<group>";
};
33CC11242044D66E0003C045 /* Resources */ = {
isa = PBXGroup;
children = (
33CC10F22044A3C60003C045 /* Assets.xcassets */,
33CC10F42044A3C60003C045 /* MainMenu.xib */,
33CC10F72044A3C60003C045 /* Info.plist */,
);
name = Resources;
path = ..;
sourceTree = "<group>";
};
33CEB47122A05771004F2AC0 /* Flutter */ = {
isa = PBXGroup;
children = (
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,
33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,
33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,
33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,
);
path = Flutter;
sourceTree = "<group>";
};
33FAB671232836740065AC1E /* Runner */ = {
isa = PBXGroup;
children = (
33CC10F02044A3C60003C045 /* AppDelegate.swift */,
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,
33E51913231747F40026EE4D /* DebugProfile.entitlements */,
33E51914231749380026EE4D /* Release.entitlements */,
33CC11242044D66E0003C045 /* Resources */,
33BA886A226E78AF003329D5 /* Configs */,
);
path = Runner;
sourceTree = "<group>";
};
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
isa = PBXGroup;
children = (
6B451012A2EB682A5199F610 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
33CC10EC2044A3C60003C045 /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
AFBF2BCAB0A65734F883B596 /* [CP] Check Pods Manifest.lock */,
33CC10E92044A3C60003C045 /* Sources */,
33CC10EA2044A3C60003C045 /* Frameworks */,
33CC10EB2044A3C60003C045 /* Resources */,
33CC110E2044A8840003C045 /* Bundle Framework */,
3399D490228B24CF009A79C7 /* ShellScript */,
4C068521E38575C134D7A34F /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
33CC11202044C79F0003C045 /* PBXTargetDependency */,
);
name = Runner;
productName = Runner;
productReference = 33CC10ED2044A3C60003C045 /* webview_window_example.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
33CC10E52044A3C60003C045 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 1430;
ORGANIZATIONNAME = "";
TargetAttributes = {
33CC10EC2044A3C60003C045 = {
CreatedOnToolsVersion = 9.2;
LastSwiftMigration = 1100;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.Sandbox = {
enabled = 1;
};
};
};
33CC111A2044C6BA0003C045 = {
CreatedOnToolsVersion = 9.2;
ProvisioningStyle = Manual;
};
};
};
buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 33CC10E42044A3C60003C045;
productRefGroup = 33CC10EE2044A3C60003C045 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
33CC10EC2044A3C60003C045 /* Runner */,
33CC111A2044C6BA0003C045 /* Flutter Assemble */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
33CC10EB2044A3C60003C045 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3399D490228B24CF009A79C7 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n";
};
33CC111E2044C6BF0003C045 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
Flutter/ephemeral/FlutterInputs.xcfilelist,
);
inputPaths = (
Flutter/ephemeral/tripwire,
);
outputFileListPaths = (
Flutter/ephemeral/FlutterOutputs.xcfilelist,
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
};
4C068521E38575C134D7A34F /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
AFBF2BCAB0A65734F883B596 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
33CC10E92044A3C60003C045 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */,
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */,
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
33CC11202044C79F0003C045 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */;
targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
33CC10F42044A3C60003C045 /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
33CC10F52044A3C60003C045 /* Base */,
);
name = MainMenu.xib;
path = Runner;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
338D0CE9231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Profile;
};
338D0CEA231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.12;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
name = Profile;
};
338D0CEB231458BD00FA5F75 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Profile;
};
33CC10F92044A3C60003C045 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
33CC10FA2044A3C60003C045 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
};
name = Release;
};
33CC10FC2044A3C60003C045 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.12;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
33CC10FD2044A3C60003C045 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.12;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
name = Release;
};
33CC111C2044C6BA0003C045 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
33CC111D2044C6BA0003C045 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC10F92044A3C60003C045 /* Debug */,
33CC10FA2044A3C60003C045 /* Release */,
338D0CE9231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC10FC2044A3C60003C045 /* Debug */,
33CC10FD2044A3C60003C045 /* Release */,
338D0CEA231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = {
isa = XCConfigurationList;
buildConfigurations = (
33CC111C2044C6BA0003C045 /* Debug */,
33CC111D2044C6BA0003C045 /* Release */,
338D0CEB231458BD00FA5F75 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 33CC10E52044A3C60003C045 /* Project object */;
}

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View file

@ -1,87 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1430"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "webview_window_example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "webview_window_example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "webview_window_example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
BuildableName = "webview_window_example.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View file

@ -1,9 +0,0 @@
import Cocoa
import FlutterMacOS
@NSApplicationMain
class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
}

View file

@ -1,68 +0,0 @@
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_16.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_32.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "app_icon_64.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_256.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_512.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "app_icon_1024.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -1,340 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19162" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19162"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="webview_window_example" customModuleProvider="target">
<connections>
<outlet property="applicationMenu" destination="uQy-DD-JDr" id="XBo-yE-nKs"/>
<outlet property="mainFlutterWindow" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
</connections>
</customObject>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="APP_NAME" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="APP_NAME" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About APP_NAME" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide APP_NAME" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="-1" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit APP_NAME" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="5QF-Oa-p0T">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="W48-6f-4Dl">
<items>
<menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
<connections>
<action selector="undo:" target="-1" id="M6e-cu-g7V"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
<connections>
<action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
<menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
<connections>
<action selector="cut:" target="-1" id="YJe-68-I9s"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
<connections>
<action selector="copy:" target="-1" id="G1f-GL-Joy"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
<connections>
<action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
</connections>
</menuItem>
<menuItem title="Delete" id="pa3-QI-u2k">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
<connections>
<action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
<menuItem title="Find" id="4EN-yA-p0u">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Find" id="1b7-l0-nxx">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
<connections>
<action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
</connections>
</menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
<connections>
<action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
<connections>
<action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
<connections>
<action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
<connections>
<action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
<connections>
<action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
<connections>
<action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
<menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="9ic-FL-obx">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
<items>
<menuItem title="Show Substitutions" id="z6F-FW-3nz">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
<menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" id="hQb-2v-fYv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="rgM-f4-ycn">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
</connections>
</menuItem>
<menuItem title="Smart Links" id="cwL-P1-jid">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
</connections>
</menuItem>
<menuItem title="Data Detectors" id="tRr-pd-1PS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="HFQ-gK-NFA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="2oI-Rn-ZJC">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="c8a-y6-VQd">
<items>
<menuItem title="Make Upper Case" id="vmV-6d-7jI">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="d9M-CD-aMd">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="UEZ-Bs-lqG">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="xrE-MZ-jX0">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Speech" id="3rS-ZA-NoH">
<items>
<menuItem title="Start Speaking" id="Ynk-f8-cLZ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="Oyz-dy-DGm">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">
<items>
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
<point key="canvasLocation" x="142" y="-258"/>
</menu>
<window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="webview_window_example" customModuleProvider="target">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<rect key="contentRect" x="335" y="390" width="800" height="600"/>
<rect key="screenRect" x="0.0" y="0.0" width="1792" height="1095"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="800" height="600"/>
<autoresizingMask key="autoresizingMask"/>
</view>
<point key="canvasLocation" x="68" y="227"/>
</window>
</objects>
</document>

View file

@ -1,14 +0,0 @@
// Application-level settings for the Runner target.
//
// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
// future. If not, the values below would default to using the project name when this becomes a
// 'flutter create' template.
// The application's name. By default this is also the title of the Flutter window.
PRODUCT_NAME = webview_window_example
// The application's bundle identifier
PRODUCT_BUNDLE_IDENTIFIER = com.example.webviewWindowExample
// The copyright displayed in application information
PRODUCT_COPYRIGHT = Copyright © 2021 com.example. All rights reserved.

View file

@ -1,2 +0,0 @@
#include "../../Flutter/Flutter-Debug.xcconfig"
#include "Warnings.xcconfig"

View file

@ -1,2 +0,0 @@
#include "../../Flutter/Flutter-Release.xcconfig"
#include "Warnings.xcconfig"

View file

@ -1,13 +0,0 @@
WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
GCC_WARN_UNDECLARED_SELECTOR = YES
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
CLANG_WARN_PRAGMA_PACK = YES
CLANG_WARN_STRICT_PROTOTYPES = YES
CLANG_WARN_COMMA = YES
GCC_WARN_STRICT_SELECTOR_MATCH = YES
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
GCC_WARN_SHADOW = YES
CLANG_WARN_UNREACHABLE_CODE = YES

View file

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>

View file

@ -1,37 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
</dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>$(PRODUCT_COPYRIGHT)</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View file

@ -1,15 +0,0 @@
import Cocoa
import FlutterMacOS
class MainFlutterWindow: NSWindow {
override func awakeFromNib() {
let flutterViewController = FlutterViewController.init()
let windowFrame = self.frame
self.contentViewController = flutterViewController
self.setFrame(windowFrame, display: true)
RegisterGeneratedPlugins(registry: flutterViewController)
super.awakeFromNib()
}
}

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>

View file

@ -1,308 +0,0 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
async:
dependency: transitive
description:
name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
version: "2.11.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
characters:
dependency: transitive
description:
name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
clock:
dependency: transitive
description:
name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev"
source: hosted
version: "1.1.1"
collection:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.18.0"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
url: "https://pub.dev"
source: hosted
version: "1.0.8"
desktop_webview_window:
dependency: "direct main"
description:
path: ".."
relative: true
source: path
version: "0.2.3"
fake_async:
dependency: transitive
description:
name: fake_async
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
ffi:
dependency: transitive
description:
name: ffi
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493
url: "https://pub.dev"
source: hosted
version: "1.0.4"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
url: "https://pub.dev"
source: hosted
version: "10.0.4"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
url: "https://pub.dev"
source: hosted
version: "3.0.3"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
lints:
dependency: transitive
description:
name: lints
sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c
url: "https://pub.dev"
source: hosted
version: "1.0.1"
matcher:
dependency: transitive
description:
name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev"
source: hosted
version: "0.12.16+1"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev"
source: hosted
version: "0.8.0"
meta:
dependency: transitive
description:
name: meta
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.12.0"
path:
dependency: transitive
description:
name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev"
source: hosted
version: "1.9.0"
path_provider:
dependency: "direct main"
description:
name: path_provider
sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161
url: "https://pub.dev"
source: hosted
version: "2.1.3"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: bca87b0165ffd7cdb9cad8edd22d18d2201e886d9a9f19b4fb3452ea7df3a72a
url: "https://pub.dev"
source: hosted
version: "2.2.6"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
url: "https://pub.dev"
source: hosted
version: "2.4.0"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.dev"
source: hosted
version: "2.2.1"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
platform:
dependency: transitive
description:
name: platform
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
url: "https://pub.dev"
source: hosted
version: "3.1.5"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.dev"
source: hosted
version: "2.1.8"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_span:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.2"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
url: "https://pub.dev"
source: hosted
version: "0.7.0"
vector_math:
dependency: transitive
description:
name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
url: "https://pub.dev"
source: hosted
version: "14.2.1"
win32:
dependency: transitive
description:
name: win32
sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
url: "https://pub.dev"
source: hosted
version: "5.5.1"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
url: "https://pub.dev"
source: hosted
version: "1.0.4"
sdks:
dart: ">=3.4.0 <4.0.0"
flutter: ">=3.22.0"

View file

@ -1,85 +0,0 @@
name: webview_window_example
description: Demonstrates how to use the webview_window plugin.
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
environment:
sdk: ">=2.14.0 <3.0.0"
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
desktop_webview_window:
# When depending on this package from a real application you should use:
# webview_window: ^x.y.z
# See https://dart.dev/tools/pub/dependencies#version-constraints
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../
path_provider: ^2.0.7
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
dev_dependencies:
flutter_test:
sdk: flutter
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^1.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages

View file

@ -1,8 +0,0 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility that Flutter provides. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
void main() {}

View file

@ -1,18 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Redirect if login</title>
</head>
<body>
Auto redirect after to 2 seconds.
<script type="application/javascript">
setTimeout(function () {
window.location.href = "login_success?username=test&token=xxxxx";
}, 2000);
</script>
</body>
</html>

View file

@ -1,99 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test Webview Window</title>
<script type="application/javascript">
function readCookie() {
document.getElementById("cookie_text").innerText = document.cookie;
}
function postSimpleMessage() {
if (window.webkit) {
window.webkit.messageHandlers.test.postMessage("Hello");
}
}
function postMapMessage() {
if (window.webkit) {
window.webkit.messageHandlers.test.postMessage({"key1": 0, "key2": "value"});
}
}
function promptMessage() {
let result = prompt("test", "hello");
document.getElementById("prompt_result").innerText = result;
}
function updateCookie() {
document.cookie = "username=test; date=2021"
}
</script>
</head>
<body>
Hello World!
<p id="context">
</p>
<br/>
<button type="button" onclick="postSimpleMessage()">PostSimpleMessage</button>
<button type="button" onclick="postMapMessage()">PostMapMessage</button>
<br/>
<button type="button" onclick="promptMessage()">PromptMessage</button>
<p id="prompt_result">
</p>
<br>
<button type="button" onclick="updateCookie()">updateCookie</button>
<p id="cookie_text"></p>
<br>
<p id="user_agent_text"></p>
<script type="application/javascript">
function getMixinContext() {
let ctx = {};
if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.MixinContext) {
ctx = JSON.parse(prompt('MixinContext.getContext()'))
ctx.platform = ctx.platform || 'iOS'
} else if (window.MixinContext && (typeof window.MixinContext.getContext === 'function')) {
ctx = JSON.parse(window.MixinContext.getContext())
ctx.platform = ctx.platform || 'Android'
}
return ctx
}
let context = getMixinContext();
var e = window.document.getElementById("context");
if (context === undefined) {
e.innerText = "context not defined";
} else {
e.innerText = JSON.stringify(context);
}
</script>
<script type="application/javascript">
// document.getElementById("prompt_result").innerText = prompt("init");
readCookie()
document.getElementById("user_agent_text").innerText = navigator.userAgent;
</script>
</body>
</html>

View file

@ -1,199 +0,0 @@
// You have generated a new plugin project without
// specifying the `--platforms` flag. A plugin project supports no platforms is generated.
// To add platforms, run `flutter create -t plugin --platforms <platforms> .` under the same
// directory. You can also find a detailed instruction on how to add platforms in the `pubspec.yaml` at https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms.
import 'dart:async';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:path/path.dart' as p;
import 'src/create_configuration.dart';
import 'src/message_channel.dart';
import 'src/webview.dart';
import 'src/webview_impl.dart';
export 'src/create_configuration.dart';
export 'src/title_bar.dart';
export 'src/webview.dart';
final List<WebviewImpl> _webviews = [];
class WebviewWindow {
static const MethodChannel _channel = MethodChannel('webview_window');
static const _otherIsolateMessageHandler = ClientMessageChannel();
static bool _inited = false;
static void _init() {
if (_inited) {
return;
}
_inited = true;
_channel.setMethodCallHandler((call) async {
try {
return await _handleMethodCall(call);
} catch (e, s) {
debugPrint("method: ${call.method} args: ${call.arguments}");
debugPrint('handleMethodCall error: $e $s');
}
});
_otherIsolateMessageHandler.setMessageHandler((call) async {
try {
return await _handleOtherIsolateMethodCall(call);
} catch (e, s) {
debugPrint('_handleOtherIsolateMethodCall error: $e $s');
}
});
}
/// Check if WebView runtime is available on the current devices.
static Future<bool> isWebviewAvailable() async {
if (Platform.isWindows) {
final ret = await _channel.invokeMethod<bool>('isWebviewAvailable');
return ret == true;
}
return true;
}
static Future<Webview> create({
CreateConfiguration? configuration,
}) async {
configuration ??= CreateConfiguration.platform();
_init();
final viewId = await _channel.invokeMethod(
"create",
configuration.toMap(),
) as int;
final webview = WebviewImpl(viewId, _channel);
_webviews.add(webview);
return webview;
}
static Future<dynamic> _handleOtherIsolateMethodCall(MethodCall call) async {
final webViewId = call.arguments['webViewId'] as int;
final webView = _webviews
.cast<WebviewImpl?>()
.firstWhere((w) => w?.viewId == webViewId, orElse: () => null);
if (webView == null) {
return;
}
switch (call.method) {
case 'onBackPressed':
await webView.back();
break;
case 'onForwardPressed':
await webView.forward();
break;
case 'onRefreshPressed':
await webView.reload();
break;
case 'onStopPressed':
await webView.stop();
break;
case 'onClosePressed':
webView.close();
break;
}
}
static Future<dynamic> _handleMethodCall(MethodCall call) async {
final args = call.arguments as Map;
final viewId = args['id'] as int;
final webview = _webviews
.cast<WebviewImpl?>()
.firstWhere((e) => e?.viewId == viewId, orElse: () => null);
assert(webview != null);
if (webview == null) {
return;
}
switch (call.method) {
case "onWindowClose":
_webviews.remove(webview);
webview.onClosed();
break;
case "onJavaScriptMessage":
webview.onJavaScriptMessage(args['name'], args['body']);
break;
case "runJavaScriptTextInputPanelWithPrompt":
return webview.onRunJavaScriptTextInputPanelWithPrompt(
args['prompt'],
args['defaultText'],
);
case "onHistoryChanged":
webview.onHistoryChanged(args['canGoBack'], args['canGoForward']);
await _otherIsolateMessageHandler.invokeMethod('onHistoryChanged', {
'webViewId': viewId,
'canGoBack': args['canGoBack'] as bool,
'canGoForward': args['canGoForward'] as bool,
});
break;
case "onNavigationStarted":
webview.onNavigationStarted();
await _otherIsolateMessageHandler.invokeMethod('onNavigationStarted', {
'webViewId': viewId,
});
break;
case "onUrlRequested":
final url = args['url'] as String;
webview.notifyUrlChanged(url);
await _otherIsolateMessageHandler.invokeMethod('onUrlRequested', {
'webViewId': viewId,
'url': url,
});
break;
case "onWebMessageReceived":
final message = args['message'] as String;
webview.notifyWebMessageReceived(message);
await _otherIsolateMessageHandler.invokeMethod('onWebMessageReceived', {
'webViewId': viewId,
'message': message,
});
break;
case "onNavigationCompleted":
webview.onNavigationCompleted();
await _otherIsolateMessageHandler
.invokeMethod('onNavigationCompleted', {
'webViewId': viewId,
});
break;
default:
return;
}
}
/// Clear all cookies and storage.
static Future<void> clearAll({
String userDataFolderWindows = 'webview_window_WebView2',
}) async {
await _channel.invokeMethod('clearAll');
// FIXME(boyan01) Move the logic to windows platform if WebView2 provider a way to clean caches.
// https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/user-data-folder#create-user-data-folders
if (Platform.isWindows) {
final Directory webview2Dir;
if (p.isAbsolute(userDataFolderWindows)) {
webview2Dir = Directory(userDataFolderWindows);
} else {
webview2Dir = Directory(p.join(
p.dirname(Platform.resolvedExecutable), userDataFolderWindows));
}
if (await (webview2Dir.exists())) {
for (var i = 0; i <= 4; i++) {
try {
await webview2Dir.delete(recursive: true);
break;
} catch (e) {
debugPrint("delete cache failed. retring.... $e");
}
// wait to ensure all web window has been closed and file handle has been release.
await Future.delayed(const Duration(seconds: 1));
}
}
}
}
}

View file

@ -1,54 +0,0 @@
import 'dart:io';
class CreateConfiguration {
final int windowWidth;
final int windowHeight;
/// Position of the top left point of the webview window
final int windowPosX;
final int windowPosY;
/// the title of window
final String title;
final int titleBarHeight;
final int titleBarTopPadding;
final String userDataFolderWindows;
final bool useWindowPositionAndSize;
final bool openMaximized;
const CreateConfiguration({
this.windowWidth = 1280,
this.windowHeight = 720,
this.windowPosX = 0,
this.windowPosY = 0,
this.title = "",
this.titleBarHeight = 40,
this.titleBarTopPadding = 0,
this.userDataFolderWindows = 'webview_window_WebView2',
this.useWindowPositionAndSize = false,
this.openMaximized = false,
});
factory CreateConfiguration.platform() {
return CreateConfiguration(
titleBarTopPadding: Platform.isMacOS ? 24 : 0,
);
}
Map toMap() => {
"windowWidth": windowWidth,
"windowHeight": windowHeight,
"windowPosX": windowPosX,
"windowPosY": windowPosY,
"title": title,
"titleBarHeight": titleBarHeight,
"titleBarTopPadding": titleBarTopPadding,
"userDataFolderWindows": userDataFolderWindows,
"useWindowPositionAndSize": useWindowPositionAndSize,
"openMaximized": openMaximized,
};
}

View file

@ -1,17 +0,0 @@
import 'package:flutter/services.dart';
typedef MessageHandler = Future<dynamic> Function(MethodCall call);
class ClientMessageChannel {
const ClientMessageChannel();
static const _channel = MethodChannel('webview_message/client_channel');
Future<dynamic> invokeMethod(String method, [dynamic arguments]) {
return _channel.invokeMethod(method, arguments);
}
void setMessageHandler(MessageHandler? handler) {
_channel.setMethodCallHandler(handler);
}
}

View file

@ -1,255 +0,0 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'message_channel.dart';
const _channel = ClientMessageChannel();
/// runs the title bar
/// title bar is a widget that displays the title of the webview window
/// return true if the args is matchs the title bar
///
/// [builder] custom TitleBar widget builder.
/// can use [TitleBarWebViewController] to controller the WebView
/// use [TitleBarWebViewState] to triger the title bar status.
///
bool runWebViewTitleBarWidget(
List<String> args, {
WidgetBuilder? builder,
Color? backgroundColor,
void Function(Object error, StackTrace stack)? onError,
}) {
if (args.isEmpty || args[0] != 'web_view_title_bar') {
return false;
}
final webViewId = int.tryParse(args[1]);
if (webViewId == null) {
return false;
}
final titleBarTopPadding = int.tryParse(args.length > 2 ? args[2] : '0') ?? 0;
runZonedGuarded(
() {
WidgetsFlutterBinding.ensureInitialized();
runApp(_TitleBarApp(
webViewId: webViewId,
titleBarTopPadding: titleBarTopPadding,
backgroundColor: backgroundColor,
builder: builder ?? _defaultTitleBar,
));
},
onError ??
(e, s) {
debugPrint('WebViewTitleBar: unhandled expections: $e, $s');
},
);
return true;
}
mixin TitleBarWebViewController {
static TitleBarWebViewController of(BuildContext context) {
final state = context.findAncestorStateOfType<_TitleBarAppState>();
assert(state != null,
'only can find TitleBarWebViewController in widget which run from runWebViewTitleBarWidget');
return state!;
}
int get _webViewId;
/// navigate back
void back() {
_channel.invokeMethod('onBackPressed', {
'webViewId': _webViewId,
});
}
/// navigate forward
void forward() {
_channel.invokeMethod('onForwardPressed', {
'webViewId': _webViewId,
});
}
/// reload the webview
void reload() {
_channel.invokeMethod('onRefreshPressed', {
'webViewId': _webViewId,
});
}
/// stop loading the webview
void stop() {
_channel.invokeMethod('onStopPressed', {
'webViewId': _webViewId,
});
}
/// close the webview
void close() {
_channel.invokeMethod('onClosePressed', {
'webViewId': _webViewId,
});
}
}
class TitleBarWebViewState extends InheritedWidget {
const TitleBarWebViewState({
Key? key,
required Widget child,
required this.isLoading,
required this.canGoBack,
required this.canGoForward,
required this.url,
}) : super(key: key, child: child);
final bool isLoading;
final bool canGoBack;
final bool canGoForward;
final String? url;
static TitleBarWebViewState of(BuildContext context) {
final TitleBarWebViewState? result =
context.dependOnInheritedWidgetOfExactType<TitleBarWebViewState>();
assert(result != null, 'No WebViewState found in context');
return result!;
}
@override
bool updateShouldNotify(TitleBarWebViewState oldWidget) {
return isLoading != oldWidget.isLoading ||
canGoBack != oldWidget.canGoBack ||
canGoForward != oldWidget.canGoForward;
}
}
class _TitleBarApp extends StatefulWidget {
const _TitleBarApp({
Key? key,
required this.webViewId,
required this.titleBarTopPadding,
required this.builder,
this.backgroundColor,
}) : super(key: key);
final int webViewId;
final int titleBarTopPadding;
final WidgetBuilder builder;
final Color? backgroundColor;
@override
State<_TitleBarApp> createState() => _TitleBarAppState();
}
class _TitleBarAppState extends State<_TitleBarApp>
with TitleBarWebViewController {
bool _canGoBack = false;
bool _canGoForward = false;
bool _isLoading = false;
String? _url;
@override
int get _webViewId => widget.webViewId;
@override
void initState() {
super.initState();
_channel.setMessageHandler((call) async {
final args = call.arguments as Map;
final webViewId = args['webViewId'] as int;
if (webViewId != widget.webViewId) {
return;
}
switch (call.method) {
case "onHistoryChanged":
setState(() {
_canGoBack = args['canGoBack'] as bool;
_canGoForward = args['canGoForward'] as bool;
});
break;
case "onNavigationStarted":
setState(() {
_isLoading = true;
});
break;
case "onNavigationCompleted":
setState(() {
_isLoading = false;
});
break;
case "onUrlRequested":
setState(() {
_url = args['url'] as String;
});
break;
}
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Material(
color:
widget.backgroundColor ?? Theme.of(context).scaffoldBackgroundColor,
child: Padding(
padding: EdgeInsets.only(top: widget.titleBarTopPadding.toDouble()),
child: TitleBarWebViewState(
isLoading: _isLoading,
canGoBack: _canGoBack,
canGoForward: _canGoForward,
url: _url,
child: Builder(builder: widget.builder),
),
),
),
);
}
}
Widget _defaultTitleBar(BuildContext context) {
final state = TitleBarWebViewState.of(context);
final controller = TitleBarWebViewController.of(context);
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
IconButton(
padding: EdgeInsets.zero,
splashRadius: 16,
iconSize: 16,
onPressed: !state.canGoBack ? null : controller.back,
icon: const Icon(Icons.arrow_back),
),
IconButton(
padding: EdgeInsets.zero,
splashRadius: 16,
iconSize: 16,
onPressed: !state.canGoForward ? null : controller.forward,
icon: const Icon(Icons.arrow_forward),
),
if (state.isLoading)
IconButton(
padding: EdgeInsets.zero,
splashRadius: 16,
iconSize: 16,
onPressed: controller.stop,
icon: const Icon(Icons.close),
)
else
IconButton(
padding: EdgeInsets.zero,
splashRadius: 16,
iconSize: 16,
onPressed: controller.reload,
icon: const Icon(Icons.refresh),
),
const Spacer()
],
);
}

View file

@ -1,93 +0,0 @@
import 'package:flutter/foundation.dart';
/// Handle custom message from JavaScript in your app.
typedef JavaScriptMessageHandler = void Function(String name, dynamic body);
typedef PromptHandler = String Function(String prompt, String defaultText);
typedef OnHistoryChangedCallback = void Function(
bool canGoBack, bool canGoForward);
/// Callback when WebView start to load a URL.
/// [url] is the URL string.
typedef OnUrlRequestCallback = void Function(String url);
/// Callback when WebView receives a web message
/// [message] constains the webmessage
typedef OnWebMessageReceivedCallback = void Function(String message);
abstract class Webview {
Future<void> get onClose;
/// true if the webview is currently loading a page.
ValueListenable<bool> get isNavigating;
/// Install a message handler that you can call from your Javascript code.
///
/// available: macOS (10.10+)
void registerJavaScriptMessageHandler(
String name, JavaScriptMessageHandler handler);
/// available: macOS
void unregisterJavaScriptMessageHandler(String name);
/// available: macOS
void setPromptHandler(PromptHandler? handler);
/// Navigates to the given URL.
void launch(String url);
/// change webview theme.
///
/// available only: macOS (Brightness.dark only 10.14+)
void setBrightness(Brightness? brightness);
void addScriptToExecuteOnDocumentCreated(String javaScript);
/// Append a string to the webview's user-agent.
Future<void> setApplicationNameForUserAgent(String applicationName);
/// Navigate to the previous page in the history.
Future<void> back();
/// Navigate to the next page in the history.
Future<void> forward();
/// Show or hide webview window
Future<void> setWebviewWindowVisibility(bool visible);
/// Reload the current page.
Future<void> reload();
/// Stop all navigations and pending resource fetches.
Future<void> stop();
/// Opens the Browser DevTools in a separate window
Future<void> openDevToolsWindow();
/// Register a callback that will be invoked when the webview history changes.
void setOnHistoryChangedCallback(OnHistoryChangedCallback? callback);
void addOnUrlRequestCallback(OnUrlRequestCallback callback);
void removeOnUrlRequestCallback(OnUrlRequestCallback callback);
void addOnWebMessageReceivedCallback(OnWebMessageReceivedCallback callback);
void removeOnWebMessageReceivedCallback(
OnWebMessageReceivedCallback callback);
/// Close the web view window.
void close();
/// evaluate JavaScript in the web view.
Future<String?> evaluateJavaScript(String javaScript);
/// post a web message as String to the top level document in this WebView
Future<void> postWebMessageAsString(String webMessage);
/// post a web message as JSON to the top level document in this WebView
Future<void> postWebMessageAsJson(String webMessage);
Future<List<Map<String, dynamic>>> getCookies(String url);
}

View file

@ -1,285 +0,0 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'webview.dart';
class WebviewImpl extends Webview {
final int viewId;
final MethodChannel channel;
final Map<String, JavaScriptMessageHandler> _javaScriptMessageHandlers = {};
bool _closed = false;
PromptHandler? _promptHandler;
final _closeCompleter = Completer<void>();
OnHistoryChangedCallback? _onHistoryChanged;
final ValueNotifier<bool> _isNaivgating = ValueNotifier<bool>(false);
final Set<OnUrlRequestCallback> _onUrlRequestCallbacks = {};
final Set<OnWebMessageReceivedCallback> _onWebMessageReceivedCallbacks = {};
WebviewImpl(this.viewId, this.channel);
@override
Future<void> get onClose => _closeCompleter.future;
void onClosed() {
_closed = true;
_closeCompleter.complete();
}
void onJavaScriptMessage(String name, dynamic body) {
assert(!_closed);
final handler = _javaScriptMessageHandlers[name];
assert(handler != null, "handler $name is not registed.");
handler?.call(name, body);
}
String onRunJavaScriptTextInputPanelWithPrompt(
String prompt, String defaultText) {
assert(!_closed);
return _promptHandler?.call(prompt, defaultText) ?? defaultText;
}
void onHistoryChanged(bool canGoBack, bool canGoForward) {
assert(!_closed);
_onHistoryChanged?.call(canGoBack, canGoForward);
}
void onNavigationStarted() {
_isNaivgating.value = true;
}
void notifyUrlChanged(String url) {
for (final callback in _onUrlRequestCallbacks) {
callback(url);
}
}
void notifyWebMessageReceived(String message) {
for (final callback in _onWebMessageReceivedCallbacks) {
callback(message);
}
}
void onNavigationCompleted() {
_isNaivgating.value = false;
}
@override
ValueListenable<bool> get isNavigating => _isNaivgating;
@override
void registerJavaScriptMessageHandler(
String name, JavaScriptMessageHandler handler) {
if (!Platform.isMacOS) {
return;
}
assert(!_closed);
if (_closed) {
return;
}
assert(name.isNotEmpty);
assert(!_javaScriptMessageHandlers.containsKey(name));
_javaScriptMessageHandlers[name] = handler;
channel.invokeMethod("registerJavaScripInterface", {
"viewId": viewId,
"name": name,
});
}
@override
void unregisterJavaScriptMessageHandler(String name) {
if (!Platform.isMacOS) {
return;
}
if (_closed) {
return;
}
channel.invokeMethod("unregisterJavaScripInterface", {
"viewId": viewId,
"name": name,
});
}
@override
void setPromptHandler(PromptHandler? handler) {
if (!Platform.isMacOS) {
return;
}
_promptHandler = handler;
}
@override
void launch(String url) async {
await channel.invokeMethod("launch", {
"url": url,
"viewId": viewId,
});
}
@override
void setBrightness(Brightness? brightness) {
/// -1 : system default
/// 0 : dark
/// 1 : light
if (!Platform.isMacOS) {
return;
}
channel.invokeMethod("setBrightness", {
"viewId": viewId,
"brightness": brightness?.index ?? -1,
});
}
@override
void addScriptToExecuteOnDocumentCreated(String javaScript) {
if (!(Platform.isWindows || Platform.isLinux || Platform.isMacOS)) {
return;
}
assert(javaScript.trim().isNotEmpty);
channel.invokeMethod("addScriptToExecuteOnDocumentCreated", {
"viewId": viewId,
"javaScript": javaScript,
});
}
@override
Future<void> setApplicationNameForUserAgent(String applicationName) async {
if (!(Platform.isWindows || Platform.isLinux || Platform.isMacOS)) {
return;
}
await channel.invokeMethod("setApplicationNameForUserAgent", {
"viewId": viewId,
"applicationName": applicationName,
});
}
@override
Future<void> forward() {
return channel.invokeMethod("forward", {"viewId": viewId});
}
@override
Future<void> setWebviewWindowVisibility(bool visible) {
return channel.invokeMethod("setWebviewWindowVisibility", {
"viewId": viewId,
"visible": visible,
});
}
@override
Future<void> back() {
return channel.invokeMethod("back", {"viewId": viewId});
}
@override
Future<void> reload() {
return channel.invokeMethod("reload", {"viewId": viewId});
}
@override
Future<void> stop() {
return channel.invokeMethod("stop", {"viewId": viewId});
}
@override
Future<void> openDevToolsWindow() {
return channel.invokeMethod('openDevToolsWindow', {"viewId": viewId});
}
@override
void setOnHistoryChangedCallback(OnHistoryChangedCallback? callback) {
_onHistoryChanged = callback;
}
@override
void addOnUrlRequestCallback(OnUrlRequestCallback callback) {
_onUrlRequestCallbacks.add(callback);
}
@override
void removeOnUrlRequestCallback(OnUrlRequestCallback callback) {
_onUrlRequestCallbacks.remove(callback);
}
@override
void addOnWebMessageReceivedCallback(OnWebMessageReceivedCallback callback) {
_onWebMessageReceivedCallbacks.add(callback);
}
@override
void removeOnWebMessageReceivedCallback(
OnWebMessageReceivedCallback callback) {
_onWebMessageReceivedCallbacks.remove(callback);
}
@override
void close() {
if (_closed) {
return;
}
channel.invokeMethod("close", {"viewId": viewId});
}
@override
Future<String?> evaluateJavaScript(String javaScript) async {
final dynamic result = await channel.invokeMethod("evaluateJavaScript", {
"viewId": viewId,
"javaScriptString": javaScript,
});
if (result is String || result == null) {
return result;
}
return json.encode(result);
}
@override
Future<void> postWebMessageAsString(String webMessage) async {
return channel.invokeMethod("postWebMessageAsString", {
"viewId": viewId,
"webMessage": webMessage,
});
}
@override
Future<void> postWebMessageAsJson(String webMessage) async {
return channel.invokeMethod("postWebMessageAsJson", {
"viewId": viewId,
"webMessage": webMessage,
});
}
@override
Future<List<Map<String, dynamic>>> getCookies(String url) async {
final cookieListMap =
await channel.invokeMethod<List>('getCookies', {'url': url}) ?? [];
List<Map<String, dynamic>> cookies = [];
for (var cookieMap in cookieListMap) {
cookies.add({
if (cookieMap["name"] != null) "name": cookieMap["name"],
if (cookieMap["value"] != null) "value": cookieMap["value"],
if (cookieMap["expiresDate"] != null)
"expiresDate": cookieMap["expiresDate"],
if (cookieMap["isSessionOnly"] != null)
"isSessionOnly": cookieMap["isSessionOnly"],
if (cookieMap["domain"] != null) "domain": cookieMap["domain"],
if (cookieMap["isSecure"] != null) "isSecure": cookieMap["isSecure"],
if (cookieMap["isHttpOnly"] != null)
"isHttpOnly": cookieMap["isHttpOnly"],
if (cookieMap["path"] != null) "path": cookieMap["path"]
});
}
return cookies;
}
}

View file

@ -1,328 +0,0 @@
import Cocoa
import FlutterMacOS
import WebKit
private var viewId: Int64 = 0
public class DesktopWebviewWindowPlugin: NSObject, FlutterPlugin {
private let methodChannel: FlutterMethodChannel
private var webviews: [Int64: WebviewWindowController] = [:]
public init(methodChannel: FlutterMethodChannel) {
self.methodChannel = methodChannel
super.init()
}
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "webview_window", binaryMessenger: registrar.messenger)
let instance = DesktopWebviewWindowPlugin(methodChannel: channel)
registrar.addMethodCallDelegate(instance, channel: channel)
ClientMessageChannelPlugin.register(with: registrar)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "create":
guard let argument = call.arguments as? [String: Any?] else {
result(FlutterError(code: "0", message: "arg is not map", details: nil))
return
}
let width = argument["windowWidth"] as? Int ?? 1280
let height = argument["windowHeight"] as? Int ?? 720
let title = argument["title"] as? String ?? ""
let titleBarHeight = argument["titleBarHeight"] as? Int ?? 50
let titleBarTopPadding = argument["titleBarTopPadding"] as? Int ?? 0
let controller = WebviewWindowController(
viewId: viewId, methodChannel: methodChannel,
width: width, height: height, title: title,
titleBarHeight: titleBarHeight, titleBarTopPadding: titleBarTopPadding
)
controller.webviewPlugin = self
webviews[viewId] = controller
controller.showWindow(nil)
result(viewId)
viewId += 1
break
case "getCookies":
guard let argument = call.arguments as? [String: Any?] else {
result(FlutterError(code: "0", message: "arg is not map", details: nil))
return
}
guard let url = argument["url"] as? String else {
result(FlutterError(code: "0", message: "param url not found", details: nil))
return
}
var cookieList: [[String: Any?]] = []
if let urlHost = URL(string: url)?.host {
WKWebsiteDataStore.default().httpCookieStore.getAllCookies { (cookies) in
for cookie in cookies {
if urlHost.hasSuffix(cookie.domain) || ".\(urlHost)".hasSuffix(cookie.domain) {
var sameSite: String? = nil
if #available(macOS 10.15, *) {
if let sameSiteValue = cookie.sameSitePolicy?.rawValue {
sameSite = sameSiteValue.prefix(1).capitalized + sameSiteValue.dropFirst()
}
}
var expiresDateTimestamp: Int64 = -1
if let expiresDate = cookie.expiresDate?.timeIntervalSince1970 {
// convert to milliseconds
expiresDateTimestamp = Int64(expiresDate * 1000)
}
cookieList.append([
"name": cookie.name,
"value": cookie.value,
"expiresDate": expiresDateTimestamp != -1 ? expiresDateTimestamp : nil,
"isSessionOnly": cookie.isSessionOnly,
"domain": cookie.domain,
"sameSite": sameSite,
"isSecure": cookie.isSecure,
"isHttpOnly": cookie.isHTTPOnly,
"path": cookie.path,
])
}
}
result(cookieList)
}
return
}
result(cookieList)
break
case "launch":
guard let argument = call.arguments as? [String: Any?] else {
result(FlutterError(code: "0", message: "arg is not map", details: nil))
return
}
guard let viewId = argument["viewId"] as? Int64 else {
result(FlutterError(code: "0", message: "param viewId not found", details: nil))
return
}
guard let url = argument["url"] as? String else {
result(FlutterError(code: "0", message: "param url not found", details: nil))
return
}
guard let parsedUrl = URL(string: url) else {
result(FlutterError(code: "0", message: "failed to parse \(url)", details: nil))
return
}
guard let wc = webviews[viewId] else {
result(FlutterError(code: "0", message: "can not find webview for id: \(viewId)", details: nil))
return
}
wc.webViewController.load(url: parsedUrl)
result(nil)
break
case "registerJavaScripInterface":
guard let argument = call.arguments as? [String: Any?] else {
result(FlutterError(code: "0", message: "arg is not map", details: nil))
return
}
guard let viewId = argument["viewId"] as? Int64 else {
result(FlutterError(code: "0", message: "param viewId not found", details: nil))
return
}
guard let name = argument["name"] as? String else {
result(FlutterError(code: "0", message: "param name not found", details: nil))
return
}
guard let wc = webviews[viewId] else {
result(FlutterError(code: "0", message: "can not find webview for id: \(viewId)", details: nil))
return
}
wc.webViewController.addJavascriptInterface(name: name)
result(nil)
break
case "unregisterJavaScripInterface":
guard let argument = call.arguments as? [String: Any?] else {
result(FlutterError(code: "0", message: "arg is not map", details: nil))
return
}
guard let viewId = argument["viewId"] as? Int64 else {
result(FlutterError(code: "0", message: "param viewId not found", details: nil))
return
}
guard let name = argument["name"] as? String else {
result(FlutterError(code: "0", message: "param name not found", details: nil))
return
}
guard let wc = webviews[viewId] else {
result(FlutterError(code: "0", message: "can not find webview for id: \(viewId)", details: nil))
return
}
wc.webViewController.addJavascriptInterface(name: name)
result(nil)
break
case "clearAll":
WKWebsiteDataStore.default().removeData(
ofTypes: [WKWebsiteDataTypeCookies, WKWebsiteDataTypeLocalStorage],
modifiedSince: .distantPast,
completionHandler: {
result(nil)
})
break
case "setBrightness":
guard let argument = call.arguments as? [String: Any?] else {
result(FlutterError(code: "0", message: "arg is not map", details: nil))
return
}
guard let viewId = argument["viewId"] as? Int64 else {
result(FlutterError(code: "0", message: "param viewId not found", details: nil))
return
}
guard let wc = webviews[viewId] else {
result(FlutterError(code: "0", message: "can not find webview for id: \(viewId)", details: nil))
return
}
let brightness = argument["brightness"] as? Int ?? -1
wc.setAppearance(brightness: brightness)
result(nil)
break
case "addScriptToExecuteOnDocumentCreated":
guard let argument = call.arguments as? [String: Any?] else {
result(FlutterError(code: "0", message: "arg is not map", details: nil))
return
}
guard let viewId = argument["viewId"] as? Int64 else {
result(FlutterError(code: "0", message: "param viewId not found", details: nil))
return
}
guard let wc = webviews[viewId] else {
result(FlutterError(code: "0", message: "can not find webview for id: \(viewId)", details: nil))
return
}
guard let javaScript = argument["javaScript"] as? String else {
result(FlutterError(code: "0", message: "param javaScript not found", details: nil))
return
}
wc.webViewController.addScriptToExecuteOnDocumentCreated(javaScript: javaScript)
result(nil)
break
case "setApplicationNameForUserAgent":
guard let argument = call.arguments as? [String: Any?] else {
result(FlutterError(code: "0", message: "arg is not map", details: nil))
return
}
guard let viewId = argument["viewId"] as? Int64 else {
result(FlutterError(code: "0", message: "param viewId not found", details: nil))
return
}
guard let wc = webviews[viewId] else {
result(FlutterError(code: "0", message: "can not find webview for id: \(viewId)", details: nil))
return
}
guard let applicationName = argument["applicationName"] as? String else {
result(FlutterError(code: "0", message: "param applicationName not found", details: nil))
return
}
wc.webViewController.setApplicationNameForUserAgent(applicationName: applicationName)
result(nil)
break
case "back":
guard let argument = call.arguments as? [String: Any?] else {
result(FlutterError(code: "0", message: "arg is not map", details: nil))
return
}
guard let viewId = argument["viewId"] as? Int64 else {
result(FlutterError(code: "0", message: "param viewId not found", details: nil))
return
}
guard let wc = webviews[viewId] else {
result(FlutterError(code: "0", message: "can not find webview for id: \(viewId)", details: nil))
return
}
wc.webViewController.goBack()
break
case "forward":
guard let argument = call.arguments as? [String: Any?] else {
result(FlutterError(code: "0", message: "arg is not map", details: nil))
return
}
guard let viewId = argument["viewId"] as? Int64 else {
result(FlutterError(code: "0", message: "param viewId not found", details: nil))
return
}
guard let wc = webviews[viewId] else {
result(FlutterError(code: "0", message: "can not find webview for id: \(viewId)", details: nil))
return
}
wc.webViewController.goForward()
break
case "reload":
guard let argument = call.arguments as? [String: Any?] else {
result(FlutterError(code: "0", message: "arg is not map", details: nil))
return
}
guard let viewId = argument["viewId"] as? Int64 else {
result(FlutterError(code: "0", message: "param viewId not found", details: nil))
return
}
guard let wc = webviews[viewId] else {
result(FlutterError(code: "0", message: "can not find webview for id: \(viewId)", details: nil))
return
}
wc.webViewController.reload()
break
case "stop":
guard let argument = call.arguments as? [String: Any?] else {
result(FlutterError(code: "0", message: "arg is not map", details: nil))
return
}
guard let viewId = argument["viewId"] as? Int64 else {
result(FlutterError(code: "0", message: "param viewId not found", details: nil))
return
}
guard let wc = webviews[viewId] else {
result(FlutterError(code: "0", message: "can not find webview for id: \(viewId)", details: nil))
return
}
wc.webViewController.stopLoading()
break
case "close":
guard let argument = call.arguments as? [String: Any?] else {
result(FlutterError(code: "0", message: "arg is not map", details: nil))
return
}
guard let viewId = argument["viewId"] as? Int64 else {
result(FlutterError(code: "0", message: "param viewId not found", details: nil))
return
}
guard let wc = webviews[viewId] else {
result(FlutterError(code: "0", message: "can not find webview for id: \(viewId)", details: nil))
return
}
wc.close()
break
case "evaluateJavaScript":
guard let argument = call.arguments as? [String: Any?] else {
result(FlutterError(code: "0", message: "arg is not map", details: nil))
return
}
guard let viewId = argument["viewId"] as? Int64 else {
result(FlutterError(code: "0", message: "param viewId not found", details: nil))
return
}
guard let wc = webviews[viewId] else {
result(FlutterError(code: "0", message: "can not find webview for id: \(viewId)", details: nil))
return
}
guard let js = argument["javaScriptString"] as? String else {
result(FlutterError(code: "0", message: "param javaScriptString not found", details: nil))
return
}
wc.webViewController.evaluateJavaScript(javaScriptString: js, completer: result)
break
default:
result(FlutterMethodNotImplemented)
}
}
func onWebviewWindowClose(viewId: Int64, wc: WebviewWindowController) {
webviews.removeValue(forKey: viewId)
}
}

View file

@ -1,59 +0,0 @@
//
// MessageChannelPlugin.swift
// desktop_webview_window
//
// Created by Bin Yang on 2021/11/19.
//
import FlutterMacOS
import Foundation
public class ClientMessageChannelPlugin: NSObject, FlutterPlugin {
public init(methodChannel: FlutterMethodChannel) {
self.methodChannel = methodChannel
super.init()
}
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "webview_message/client_channel", binaryMessenger: registrar.messenger)
let instance = ClientMessageChannelPlugin(methodChannel: channel)
registrar.addMethodCallDelegate(instance, channel: channel)
ServerMessageChannel.shared.addClient(client: instance)
}
private let methodChannel: FlutterMethodChannel
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
ServerMessageChannel.shared.dispatchMethodCall(call: call, from: self)
// this is a boardcast, so we complete this with sucess.
result(nil)
}
fileprivate func invokeMethod(_ call: FlutterMethodCall) {
methodChannel.invokeMethod(call.method, arguments: call.arguments)
}
}
class ServerMessageChannel {
static let shared: ServerMessageChannel = ServerMessageChannel()
private var clients: [ClientMessageChannelPlugin] = []
func addClient(client: ClientMessageChannelPlugin) {
clients.append(client)
}
func removeClient(client: ClientMessageChannelPlugin) {
if let index = clients.firstIndex(of: client) {
clients.remove(at: index)
}
}
func dispatchMethodCall(call: FlutterMethodCall, from clientFrom: ClientMessageChannelPlugin) {
for client in clients {
if client != clientFrom {
client.invokeMethod(call)
}
}
}
}

View file

@ -1,248 +0,0 @@
//
// WebViewLayoutController.swift
// desktop_webView_window
//
// Created by Bin Yang on 2021/11/18.
//
import Cocoa
import FlutterMacOS
import WebKit
class WebViewLayoutController: NSViewController {
private lazy var titleBarController: FlutterViewController = {
let project = FlutterDartProject()
project.dartEntrypointArguments = ["web_view_title_bar", "\(viewId)", "\(titleBarTopPadding)"]
return FlutterViewController(project: project)
}()
private lazy var webView: WKWebView = {
WKWebView()
}()
private var javaScriptHandlerNames: [String] = []
weak var webViewPlugin: DesktopWebviewWindowPlugin?
private var defaultUserAgent: String?
private let methodChannel: FlutterMethodChannel
private let viewId: Int64
private let titleBarHeight: Int
private let titleBarTopPadding: Int
public init(methodChannel: FlutterMethodChannel, viewId: Int64, titleBarHeight: Int, titleBarTopPadding: Int) {
self.viewId = viewId
self.methodChannel = methodChannel
self.titleBarHeight = titleBarHeight
self.titleBarTopPadding = titleBarTopPadding
super.init(nibName: "WebViewLayoutController", bundle: Bundle(for: WebViewLayoutController.self))
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func loadView() {
super.loadView()
addChild(titleBarController)
titleBarController.view.translatesAutoresizingMaskIntoConstraints = false
// Register titlebar plugins
ClientMessageChannelPlugin.register(with: titleBarController.registrar(forPlugin: "DesktopWebviewWindowPlugin"))
let flutterView = titleBarController.view
flutterView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(flutterView)
let constraints = [
flutterView.topAnchor.constraint(equalTo: view.topAnchor),
flutterView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
flutterView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
flutterView.heightAnchor.constraint(equalToConstant: CGFloat(titleBarHeight + titleBarTopPadding)),
]
NSLayoutConstraint.activate(constraints)
view.addSubview(webView)
webView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
webView.topAnchor.constraint(equalTo: flutterView.bottomAnchor),
webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
}
override func viewDidLoad() {
super.viewDidLoad()
webView.navigationDelegate = self
webView.uiDelegate = self
// TODO(boyan01) Make it configuable from flutter.
webView.configuration.preferences.javaEnabled = true
webView.configuration.preferences.minimumFontSize = 12
webView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
webView.configuration.allowsAirPlayForMediaPlayback = true
webView.configuration.mediaTypesRequiringUserActionForPlayback = .video
webView.addObserver(self, forKeyPath: "canGoBack", options: .new, context: nil)
webView.addObserver(self, forKeyPath: "canGoForward", options: .new, context: nil)
webView.addObserver(self, forKeyPath: "loading", options: .new, context: nil)
defaultUserAgent = webView.value(forKey: "userAgent") as? String
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "canGoBack" || keyPath == "canGoForward" {
methodChannel.invokeMethod("onHistoryChanged", arguments: [
"id": viewId,
"canGoBack": webView.canGoBack,
"canGoForward": webView.canGoForward,
] as [String: Any])
} else if keyPath == "loading" {
if webView.isLoading {
methodChannel.invokeMethod("onNavigationStarted", arguments: [
"id": viewId,
])
} else {
methodChannel.invokeMethod("onNavigationCompleted", arguments: [
"id": viewId,
])
}
}
}
func load(url: URL) {
debugPrint("load url: \(url)")
webView.load(URLRequest(url: url))
}
func addJavascriptInterface(name: String) {
javaScriptHandlerNames.append(name)
webView.configuration.userContentController.add(self, name: name)
}
func removeJavascriptInterface(name: String) {
if let index = javaScriptHandlerNames.firstIndex(of: name) {
javaScriptHandlerNames.remove(at: index)
}
webView.configuration.userContentController.removeScriptMessageHandler(forName: name)
}
func addScriptToExecuteOnDocumentCreated(javaScript: String) {
webView.configuration.userContentController.addUserScript(
WKUserScript(source: javaScript, injectionTime: .atDocumentStart, forMainFrameOnly: true))
}
func setApplicationNameForUserAgent(applicationName: String) {
webView.customUserAgent = (defaultUserAgent ?? "") + applicationName
}
func destroy() {
webView.stopLoading(self)
webView.removeFromSuperview()
titleBarController.engine.shutDownEngine()
}
func reload() {
webView.reload()
}
func goBack() {
if webView.canGoBack {
webView.goBack()
}
}
func goForward() {
if webView.canGoForward {
webView.goForward()
}
}
func stopLoading() {
webView.stopLoading()
}
func evaluateJavaScript(javaScriptString: String, completer: @escaping FlutterResult) {
webView.evaluateJavaScript(javaScriptString) { result, error in
if let error = error {
completer(FlutterError(code: "1", message: error.localizedDescription, details: nil))
return
}
completer(result)
}
}
deinit {
#if DEBUG
print("\(self) deinited")
#endif
}
}
extension WebViewLayoutController: WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
guard let url = navigationAction.request.url else {
decisionHandler(.cancel)
return
}
guard ["http", "https", "file"].contains(url.scheme?.lowercased() ?? "") else {
decisionHandler(.cancel)
return
}
methodChannel.invokeMethod("onUrlRequested", arguments: [
"id": viewId,
"url": url.absoluteString,
] as [String: Any])
decisionHandler(.allow)
}
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
decisionHandler(.allow)
}
}
extension WebViewLayoutController: WKUIDelegate {
func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
methodChannel.invokeMethod(
"runJavaScriptTextInputPanelWithPrompt",
arguments: [
"id": viewId,
"prompt": prompt,
"defaultText": defaultText ?? "",
] as [String: Any]) { result in
completionHandler((result as? String) ?? "")
}
}
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if !(navigationAction.targetFrame?.isMainFrame ?? false) {
webView.load(navigationAction.request)
}
return nil
}
}
extension WebViewLayoutController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
methodChannel.invokeMethod(
"onJavaScriptMessage",
arguments: [
"id": viewId,
"name": message.name,
"body": message.body,
])
}
}

View file

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21701"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="WebViewLayoutController" customModule="desktop_webview_window" customModuleProvider="target">
<connections>
<outlet property="view" destination="Hz6-mo-xeY" id="0bl-1N-x8E"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="Hz6-mo-xeY">
<rect key="frame" x="0.0" y="0.0" width="480" height="272"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<point key="canvasLocation" x="139" y="147"/>
</customView>
</objects>
</document>

View file

@ -1,109 +0,0 @@
//
// WebviewWindowController.swift
// webview_window
//
// Created by Bin Yang on 2021/10/15.
//
import Cocoa
import FlutterMacOS
import WebKit
class WebviewWindowController: NSWindowController {
private let methodChannel: FlutterMethodChannel
private let viewId: Int64
private let width, height: Int
private let titleBarHeight: Int
private let titleBarTopPadding: Int
private let title: String
public weak var webviewPlugin: DesktopWebviewWindowPlugin?
init(viewId: Int64, methodChannel: FlutterMethodChannel,
width: Int, height: Int,
title: String, titleBarHeight: Int,
titleBarTopPadding: Int) {
self.viewId = viewId
self.methodChannel = methodChannel
self.width = width
self.height = height
self.titleBarHeight = titleBarHeight
self.titleBarTopPadding = titleBarTopPadding
self.title = title
super.init(window: nil)
let newWindow = NSWindow(contentRect: NSRect(x: 0, y: 0, width: width, height: height), styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], backing: .buffered, defer: false)
newWindow.delegate = self
newWindow.title = title
newWindow.titlebarAppearsTransparent = true
let contentViewController = WebViewLayoutController(
methodChannel: methodChannel,
viewId: viewId, titleBarHeight: titleBarHeight,
titleBarTopPadding: titleBarTopPadding)
newWindow.contentViewController = contentViewController
newWindow.setContentSize(NSSize(width: width, height: height))
newWindow.center()
window = newWindow
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public var webViewController: WebViewLayoutController {
window?.contentViewController as! WebViewLayoutController
}
override func keyDown(with event: NSEvent) {
if event.charactersIgnoringModifiers == "w" && event.modifierFlags.contains(.command) {
close()
}
}
func destroy() {
webViewController.destroy()
webviewPlugin = nil
window?.delegate = nil
window = nil
}
func setAppearance(brightness: Int) {
switch brightness {
case 0:
if #available(macOS 10.14, *) {
window?.appearance = NSAppearance(named: .darkAqua)
} else {
// Fallback on earlier versions
}
break
case 1:
window?.appearance = NSAppearance(named: .aqua)
break
default:
window?.appearance = nil
break
}
}
deinit {
#if DEBUG
print("\(self) deinited")
#endif
}
}
extension WebviewWindowController: NSWindowDelegate {
func windowWillClose(_ notification: Notification) {
webViewController.destroy()
methodChannel.invokeMethod("onWindowClose", arguments: ["id": viewId])
webviewPlugin?.onWebviewWindowClose(viewId: viewId, wc: self)
destroy()
}
}

View file

@ -1,22 +0,0 @@
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint webview_window.podspec` to validate before publishing.
#
Pod::Spec.new do |s|
s.name = 'desktop_webview_window'
s.version = '0.0.1'
s.summary = 'A new flutter plugin project.'
s.description = <<-DESC
A new flutter plugin project.
DESC
s.homepage = 'http://example.com'
s.license = { :file => '../LICENSE' }
s.author = { 'Your Company' => 'email@example.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.dependency 'FlutterMacOS'
s.platform = :osx, '10.12'
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
s.swift_version = '5.0'
end

View file

@ -1,205 +0,0 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
async:
dependency: transitive
description:
name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
version: "2.11.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
characters:
dependency: transitive
description:
name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
clock:
dependency: transitive
description:
name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev"
source: hosted
version: "1.1.1"
collection:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.18.0"
fake_async:
dependency: transitive
description:
name: fake_async
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
sha256: b543301ad291598523947dc534aaddc5aaad597b709d2426d3a0e0d44c5cb493
url: "https://pub.dev"
source: hosted
version: "1.0.4"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
url: "https://pub.dev"
source: hosted
version: "10.0.4"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
url: "https://pub.dev"
source: hosted
version: "3.0.3"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
lints:
dependency: transitive
description:
name: lints
sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c
url: "https://pub.dev"
source: hosted
version: "1.0.1"
matcher:
dependency: transitive
description:
name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev"
source: hosted
version: "0.12.16+1"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev"
source: hosted
version: "0.8.0"
meta:
dependency: transitive
description:
name: meta
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.12.0"
path:
dependency: "direct main"
description:
name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev"
source: hosted
version: "1.9.0"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_span:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.2"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
url: "https://pub.dev"
source: hosted
version: "0.7.0"
vector_math:
dependency: transitive
description:
name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
url: "https://pub.dev"
source: hosted
version: "14.2.1"
sdks:
dart: ">=3.3.0 <4.0.0"
flutter: ">=3.18.0-18.0.pre.54"

View file

@ -1,28 +0,0 @@
name: desktop_webview_window
description: Show a webview window on your flutter desktop application.
version: 0.2.3
homepage: https://github.com/MixinNetwork/flutter-plugins/tree/main/packages/desktop_webview_window
environment:
sdk: ">=2.14.0 <4.0.0"
flutter: ">=2.5.0"
dependencies:
flutter:
sdk: flutter
path: ^1.8.0
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^1.0.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
plugin:
platforms:
macos:
pluginClass: DesktopWebviewWindowPlugin

View file

@ -1 +0,0 @@
python3 -m http.server 3000 --directory example/test_web_pages

View file

@ -316,9 +316,11 @@ packages:
desktop_webview_window:
dependency: "direct main"
description:
path: "packages/desktop_webview_window"
relative: true
source: path
path: "."
ref: main
resolved-ref: "861cb573a6decb815741ed76e845fe05a3662c95"
url: "https://github.com/kodjodevf/desktop_webview_window.git"
source: git
version: "0.2.3"
directed_graph:
dependency: transitive

View file

@ -33,7 +33,9 @@ dependencies:
share_plus: ^9.0.0
xpath_selector_html_parser: ^3.0.1
desktop_webview_window:
path: ./packages/desktop_webview_window
git:
url: https://github.com/kodjodevf/desktop_webview_window.git
ref: main
archive: ^3.6.1
file_picker: ^8.0.5
path_provider: ^2.1.3
@ -101,6 +103,7 @@ flutter:
assets:
- assets/
- assets/fonts/
- assets/trackers_icons/
- assets/app_icons/
flutter_launcher_icons: