Author SHA1 Message Date
jingyun 50a1ac0af7 fix:报错处理 2026-08-14 09:39:11 +08:00
jingyun c5653a3699 feat: align shared app foundations 2026-08-13 17:47:01 +08:00
jingyun bd6bb0ffce fix:优化和对齐版本 2026-08-13 17:17:52 +08:00
133 changed files with 1045 additions and 3703 deletions

No files matched your search

+7
View File
@@ -45,3 +45,10 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release
/android/.kotlin/
# Release signing material and packaged runtime secrets are restored locally
# from the team's secure storage; never commit them.
/android/key.properties
/android/app/files/*.jks
/assets/env/.env
Binary file not shown.
+6 -6
View File
@@ -1,7 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- Debug-only local API support. Release inherits false from main. -->
<application
android:usesCleartextTraffic="true"
tools:replace="android:usesCleartextTraffic" />
</manifest>
+1 -1
View File
@@ -9,7 +9,7 @@
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:usesCleartextTraffic="true">
android:usesCleartextTraffic="false">
<activity
android:name=".MainActivity"
android:exported="true"
+6
View File
@@ -2,6 +2,12 @@ allprojects {
repositories {
google()
mavenCentral()
// android_id on the Git main branch uses EasyProtector 1.1.2. Its
// original JCenter publication is retired; Appodeal maintains it.
maven("https://maven.aliyun.com/repository/public")
maven("https://maven.aliyun.com/repository/gradle-plugin")
maven("https://maven.aliyun.com/repository/google")
maven("https://maven.aliyun.com/repository/jcenter")
}
}
-4
View File
@@ -1,4 +0,0 @@
storePassword=jinzhi123
keyPassword=jinzhi123
keyAlias=jinzhi
storeFile=files/jinzhi.jks
-6
View File
@@ -1,6 +0,0 @@
# .env file
# UMENG keys for Muzhi environment (replace with actual keys later)
UMENG_ANDROID_APP_KEY=6a27b1f46f259537c7b616be
UMENG_IOS_APP_KEY=6a27b24e6f259537c7b617a8
UMENG_ANDROID_PUSH_SECRET=xxx
# UMENG_CHANNEL is usually set via build flavors or defaults, but can be here if needed.
+4
View File
@@ -4,6 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import '../common/router/app_router.dart';
import '../common/lifecycle/refresh_coordinator.dart';
import '../common/theme/jinzhi_theme.dart';
import '../common/theme/spacing.dart';
import '../common/theme/theme_controller.dart';
@@ -13,6 +14,9 @@ class JinzhiApp extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
// Keep the app-wide foreground refresh coordinator alive. Features opt in
// by registering only while their screen is visible.
ref.watch(refreshCoordinatorProvider);
final router = ref.watch(routerProvider);
final mode = ref.watch(themeModeControllerProvider);
// DM Sans 作主字体(拉丁/数字),中文走系统级联(iOS 苹方 / Android 厂商
+6
View File
@@ -4,12 +4,18 @@ import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/widgets.dart';
import '../common/services/device_header_service.dart';
import '../common/storage/secure_identity_storage.dart';
import '../common/storage/storage_service.dart';
import '../common/widgets/easy_refresh_localization.dart';
import 'app.dart';
Future<Widget> bootstrap() async {
WidgetsFlutterBinding.ensureInitialized();
configureEasyRefreshChineseLocalization();
await StorageService.instance;
await SecureIdentityStorage(
StorageService.to.preferences,
).restoreAccessToken();
if (!kIsWeb) {
if (Platform.isAndroid) {
// Before consent this only initializes app version and channel. The
@@ -0,0 +1,84 @@
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
typedef RefreshCallback = FutureOr<void> Function();
/// Coordinates safe refresh points without owning any feature data.
///
/// A screen registers its callback while it is visible. Registered callbacks
/// run when the app returns to the foreground; callers can also request a
/// manual refresh through the returned handle.
class RefreshCoordinator with WidgetsBindingObserver {
RefreshCoordinator() {
WidgetsBinding.instance.addObserver(this);
}
final Set<_RefreshRegistration> _registrations = {};
AppLifecycleState _lifecycleState = AppLifecycleState.resumed;
bool get isForeground => _lifecycleState == AppLifecycleState.resumed;
RefreshRegistration register({
required RefreshCallback onRefresh,
bool active = true,
}) {
final registration = _RefreshRegistration(onRefresh, active);
_registrations.add(registration);
return RefreshRegistration._(this, registration);
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
_lifecycleState = state;
if (state == AppLifecycleState.resumed) refreshVisible();
}
void refreshVisible() {
for (final registration in _registrations) {
if (registration.active) unawaited(_run(registration));
}
}
Future<void> _run(_RefreshRegistration registration) async {
try {
await registration.onRefresh();
} catch (_) {
// Refresh failures belong to the owning feature's state/UI.
}
}
void dispose() {
WidgetsBinding.instance.removeObserver(this);
_registrations.clear();
}
}
class RefreshRegistration {
RefreshRegistration._(this._coordinator, this._registration);
final RefreshCoordinator _coordinator;
final _RefreshRegistration _registration;
bool get active => _registration.active;
set active(bool value) => _registration.active = value;
void refreshNow() => _coordinator._run(_registration);
void dispose() => _coordinator._registrations.remove(_registration);
}
class _RefreshRegistration {
_RefreshRegistration(this.onRefresh, this.active);
final RefreshCallback onRefresh;
bool active;
}
final refreshCoordinatorProvider = Provider<RefreshCoordinator>((ref) {
final coordinator = RefreshCoordinator();
ref.onDispose(coordinator.dispose);
return coordinator;
});
+14 -8
View File
@@ -1,16 +1,22 @@
import 'package:dio/dio.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import '../services/device_header_service.dart';
import '../storage/secure_identity_storage.dart';
import '../storage/storage_service.dart';
const _kJwtKey = 'jwt_token';
const _storage = FlutterSecureStorage();
final _defaultIdentityStorage = SecureIdentityStorage(
StorageService.to.preferences,
);
Future<void> saveJwt(String token) =>
_storage.write(key: _kJwtKey, value: token);
Future<void> clearJwt() => _storage.delete(key: _kJwtKey);
Future<String?> loadJwt() => _storage.read(key: _kJwtKey);
Future<void> saveJwt(String token) => _defaultIdentityStorage.saveJwt(token);
Future<void> clearJwt() => _defaultIdentityStorage.clearJwt();
Future<String?> loadJwt() => _defaultIdentityStorage.readJwt();
class AuthInterceptor extends Interceptor {
AuthInterceptor(this._identityStorage);
final SecureIdentityStorage _identityStorage;
@override
Future<void> onRequest(
RequestOptions options,
@@ -19,7 +25,7 @@ class AuthInterceptor extends Interceptor {
await DeviceHeaderService.to.ensureInitialized();
options.headers.addAll(DeviceHeaderService.to.commonHeaders());
options.headers.addAll(DeviceHeaderService.to.platformIdentityHeaders());
final jwt = await loadJwt();
final jwt = await _identityStorage.readJwt();
if (jwt != null && jwt.isNotEmpty) {
options.headers['Authorization'] = 'Bearer $jwt';
}
+10 -1
View File
@@ -5,6 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../config/app_config.dart';
import '../storage/secure_identity_storage.dart';
import 'auth_interceptor.dart';
import 'kratos_error_interceptor.dart';
@@ -12,12 +13,20 @@ part 'dio_provider.g.dart';
const _protobufContentType = 'application/x-protobuf';
/// Per-request override for native protobuf-over-HTTP endpoints.
Options protobufOptions() => Options(
responseType: ResponseType.bytes,
contentType: _protobufContentType,
headers: const {'Accept': _protobufContentType},
);
@Riverpod(keepAlive: true)
AppConfig appConfig(Ref ref) => AppConfig.fromEnvironment();
@Riverpod(keepAlive: true)
Dio dio(Ref ref) {
final config = ref.watch(appConfigProvider);
final identityStorage = ref.watch(secureIdentityStorageProvider);
final d = Dio(
BaseOptions(
baseUrl: config.apiBaseUrl,
@@ -31,7 +40,7 @@ Dio dio(Ref ref) {
},
),
);
d.interceptors.add(AuthInterceptor());
d.interceptors.add(AuthInterceptor(identityStorage));
d.interceptors.add(KratosErrorInterceptor());
if (!kReleaseMode) {
d.interceptors.add(LogInterceptor(requestBody: false, responseBody: false));
+9
View File
@@ -0,0 +1,9 @@
import 'package:flutter/foundation.dart';
/// Android requires explicit privacy consent before collecting device
/// identifiers. iOS follows its existing startup flow instead.
bool requiresAndroidPrivacyConsent({
required bool isWeb,
required TargetPlatform platform,
required bool privacyAgreed,
}) => !isWeb && platform == TargetPlatform.android && !privacyAgreed;
+35 -14
View File
@@ -54,22 +54,43 @@ final routerProvider = Provider<GoRouter>((ref) {
return null;
},
routes: [
ShellRoute(
builder: (context, state, child) =>
TabShell(location: state.matchedLocation, child: child),
routes: [
GoRoute(
path: AppRoutes.assets,
builder: (ctx, s) => const AssetsPage(),
StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) => TabShell(
location: state.matchedLocation,
navigationShell: navigationShell,
),
branches: [
StatefulShellBranch(
routes: [
GoRoute(
path: AppRoutes.assets,
builder: (ctx, s) => const AssetsPage(),
),
],
),
GoRoute(
path: AppRoutes.market,
builder: (ctx, s) => const MarketPage(),
StatefulShellBranch(
routes: [
GoRoute(
path: AppRoutes.market,
builder: (ctx, s) => const MarketPage(),
),
],
),
GoRoute(path: AppRoutes.news, builder: (ctx, s) => const NewsPage()),
GoRoute(
path: AppRoutes.profile,
builder: (ctx, s) => const ProfilePage(),
StatefulShellBranch(
routes: [
GoRoute(
path: AppRoutes.news,
builder: (ctx, s) => const NewsPage(),
),
],
),
StatefulShellBranch(
routes: [
GoRoute(
path: AppRoutes.profile,
builder: (ctx, s) => const ProfilePage(),
),
],
),
],
),
+14 -9
View File
@@ -8,9 +8,13 @@ import '../widgets/adaptive.dart';
import 'app_router.dart';
class TabShell extends StatefulWidget {
const TabShell({super.key, required this.child, required this.location});
const TabShell({
super.key,
required this.navigationShell,
required this.location,
});
final Widget child;
final StatefulNavigationShell navigationShell;
final String location;
@override
@@ -22,10 +26,7 @@ class _TabShellState extends State<TabShell> {
bool _showCompactHeader = false;
static const _tabs = ['/assets', '/market', '/news', '/profile'];
int get _index =>
_tabs.indexWhere((t) => widget.location.startsWith(t)).clamp(0, 3);
int get _index => widget.navigationShell.currentIndex;
@override
void didUpdateWidget(covariant TabShell oldWidget) {
@@ -104,7 +105,7 @@ class _TabShellState extends State<TabShell> {
color: cs.background,
child: NotificationListener<ScrollNotification>(
onNotification: _handleScrollNotification,
child: Stack(children: [Positioned.fill(child: widget.child)]),
child: widget.navigationShell,
),
),
bottomNavigationBar: SafeArea(
@@ -129,7 +130,7 @@ class _TabShellState extends State<TabShell> {
),
child: Row(
children: [
for (var i = 0; i < _tabs.length; i++)
for (var i = 0; i < _labels.length; i++)
Expanded(
child: _TabButton(
icon: i == _index
@@ -137,7 +138,11 @@ class _TabShellState extends State<TabShell> {
: _outlineIcons[i],
label: _labels[i],
selected: i == _index,
onTap: () => context.go(_tabs[i]),
onTap: () =>
widget.navigationShell.goBranch(
i,
initialLocation: i == _index,
),
),
),
],
+12 -8
View File
@@ -3,7 +3,7 @@ import 'dart:io' show Platform;
import 'package:android_id/android_id.dart';
import 'package:android_oaid/android_oaid.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/foundation.dart' show defaultTargetPlatform, kIsWeb;
import 'package:flutter_paid/flutter_paid.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:package_info_plus/package_info_plus.dart';
@@ -12,6 +12,7 @@ import 'package:uuid/uuid.dart';
import '../storage/storage_keys.dart';
import '../storage/storage_service.dart';
import '../privacy/privacy_gate.dart';
/// 请求公共 + 平台身份 header 来源(完全对齐研值契约)。
/// AuthInterceptor 每个请求注入 commonHeaders() + platformIdentityHeaders(),
@@ -52,9 +53,11 @@ class DeviceHeaderService {
// Align with tradingagents-flutter-app: Android only initializes device
// information after the user has accepted the privacy policy.
if (!kIsWeb &&
Platform.isAndroid &&
!StorageService.to.getBool(storagePrivacyAgreed)) {
if (requiresAndroidPrivacyConsent(
isWeb: kIsWeb,
platform: defaultTargetPlatform,
privacyAgreed: StorageService.to.getBool(storagePrivacyAgreed),
)) {
return;
}
@@ -184,10 +187,11 @@ class DeviceHeaderService {
/// 是否需要首启隐私合规确认。**仅 Android**(合规要求:同意前不得采集设备
/// 标识)。由 go_router redirect 调用,未同意则强制跳隐私页。
bool get privacyConsentRequired =>
!kIsWeb &&
Platform.isAndroid &&
!StorageService.to.getBool(storagePrivacyAgreed);
bool get privacyConsentRequired => requiresAndroidPrivacyConsent(
isWeb: kIsWeb,
platform: defaultTargetPlatform,
privacyAgreed: StorageService.to.getBool(storagePrivacyAgreed),
);
/// iOS 首次启动页:仅在首次安装后展示一次。
bool get iosStartupRequired =>
@@ -0,0 +1,98 @@
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'storage_keys.dart';
import 'storage_service.dart';
abstract interface class SecureKeyValueStorage {
Future<String?> read(String key);
Future<void> write(String key, String value);
Future<void> delete(String key);
}
class FlutterSecureKeyValueStorage implements SecureKeyValueStorage {
const FlutterSecureKeyValueStorage();
static const _storage = FlutterSecureStorage();
@override
Future<String?> read(String key) => _storage.read(key: key);
@override
Future<void> write(String key, String value) =>
_storage.write(key: key, value: value);
@override
Future<void> delete(String key) => _storage.delete(key: key);
}
/// Sensitive identity values stay behind one injectable storage boundary.
/// Legacy plaintext preferences are migrated only after a secure write works.
class SecureIdentityStorage {
SecureIdentityStorage(
this._preferences, {
SecureKeyValueStorage secureStorage = const FlutterSecureKeyValueStorage(),
}) : _storage = secureStorage;
static const _accessTokenKey = 'access_token';
static const _legacySecureJwtKey = 'jwt_token';
final SharedPreferences _preferences;
final SecureKeyValueStorage _storage;
Future<String?> restoreAccessToken() async {
final current = _normalized(await _storage.read(_accessTokenKey));
final legacyPreferences = _normalized(
_preferences.getString(storageLegacyAccessToken),
);
final legacySecure = current == null
? _normalized(await _storage.read(_legacySecureJwtKey))
: null;
final token = current ?? legacyPreferences ?? legacySecure;
if (current == null && token != null) {
await _storage.write(_accessTokenKey, token);
}
await _storage.delete(_legacySecureJwtKey);
await _preferences.remove(storageLegacyAccessToken);
if (token == null) {
await _preferences.remove(storageAuthSessionActive);
} else {
await _preferences.setBool(storageAuthSessionActive, true);
}
return token;
}
Future<String?> readJwt() async {
final token = _normalized(await _storage.read(_accessTokenKey));
if (token == null || _preferences.containsKey(storageLegacyAccessToken)) {
return restoreAccessToken();
}
return token;
}
Future<void> saveJwt(String token) async {
final normalized = _normalized(token);
if (normalized == null) {
throw ArgumentError.value(token, 'token', 'must not be empty');
}
await _storage.write(_accessTokenKey, normalized);
await _storage.delete(_legacySecureJwtKey);
await _preferences.remove(storageLegacyAccessToken);
await _preferences.setBool(storageAuthSessionActive, true);
}
Future<void> clearJwt() async {
await _storage.delete(_accessTokenKey);
await _storage.delete(_legacySecureJwtKey);
await _preferences.remove(storageLegacyAccessToken);
await _preferences.remove(storageAuthSessionActive);
}
}
final secureIdentityStorageProvider = Provider<SecureIdentityStorage>(
(ref) => SecureIdentityStorage(StorageService.to.preferences),
);
String? _normalized(String? value) {
final normalized = value?.trim() ?? '';
return normalized.isEmpty ? null : normalized;
}
+5
View File
@@ -8,6 +8,11 @@ const storageJinzhiPurityPresets = 'jinzhi_purity_presets';
const storageJinzhiPriceColorMode = 'jinzhi_price_color_mode';
const storageJinzhiMockLoggedIn = 'jinzhi_mock_logged_in';
// Previous builds could persist credentials in SharedPreferences. These keys
// exist only for one-time migration into secure storage.
const storageLegacyAccessToken = 'access_token';
const storageAuthSessionActive = 'auth_session_active';
// 设备/广告标识。由各自的 SDK/ATT 流程写入,DeviceHeaderService 读出注入
// header;未写入则为空、注入时被过滤。
const storageDeviceToken = 'device_token'; // 推送 token
+4
View File
@@ -6,6 +6,8 @@ class StorageService {
static StorageService? _instance;
static StorageService get to => _instance!;
SharedPreferences get preferences => _prefs;
static Future<StorageService> get instance async {
if (_instance != null) return _instance!;
final prefs = await SharedPreferences.getInstance();
@@ -17,4 +19,6 @@ class StorageService {
Future<void> setBool(String key, bool v) => _prefs.setBool(key, v);
String? getString(String key) => _prefs.getString(key);
Future<void> setString(String key, String v) => _prefs.setString(key, v);
bool containsKey(String key) => _prefs.containsKey(key);
Future<void> remove(String key) => _prefs.remove(key);
}
+104
View File
@@ -0,0 +1,104 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
/// 金值统一的网络图片入口。
///
/// 图片会自动使用 [CachedNetworkImage] 的磁盘缓存;业务页面不应直接创建
/// `Image.network`,以保证加载和失败状态的视觉及缓存策略一致。
class AppNetworkImage extends StatelessWidget {
const AppNetworkImage({
super.key,
required this.imageUrl,
this.width,
this.height,
this.fit = BoxFit.cover,
this.alignment = Alignment.center,
this.borderRadius,
this.cacheKey,
this.httpHeaders,
this.placeholder,
this.errorWidget,
this.semanticLabel,
});
final String imageUrl;
final double? width;
final double? height;
final BoxFit fit;
final Alignment alignment;
final BorderRadius? borderRadius;
final String? cacheKey;
final Map<String, String>? httpHeaders;
final Widget? placeholder;
final Widget? errorWidget;
final String? semanticLabel;
@override
Widget build(BuildContext context) {
final child = imageUrl.trim().isEmpty
? _ImageFallback(errorWidget: errorWidget)
: CachedNetworkImage(
imageUrl: imageUrl,
cacheKey: cacheKey,
httpHeaders: httpHeaders,
width: width,
height: height,
fit: fit,
alignment: alignment,
fadeInDuration: const Duration(milliseconds: 150),
placeholder: (_, _) =>
placeholder ?? const _ImageLoadingPlaceholder(),
errorWidget: (_, _, _) => _ImageFallback(errorWidget: errorWidget),
);
final clipped = borderRadius == null
? child
: ClipRRect(borderRadius: borderRadius!, child: child);
if (semanticLabel == null) return clipped;
return Semantics(image: true, label: semanticLabel, child: clipped);
}
}
class _ImageLoadingPlaceholder extends StatelessWidget {
const _ImageLoadingPlaceholder();
@override
Widget build(BuildContext context) {
final colors = ShadTheme.of(context).colorScheme;
return ColoredBox(
color: colors.muted,
child: Center(
child: SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
color: colors.mutedForeground,
),
),
),
);
}
}
class _ImageFallback extends StatelessWidget {
const _ImageFallback({required this.errorWidget});
final Widget? errorWidget;
@override
Widget build(BuildContext context) {
if (errorWidget != null) return errorWidget!;
final colors = ShadTheme.of(context).colorScheme;
return ColoredBox(
color: colors.muted,
child: Center(
child: Icon(
Icons.image_not_supported_outlined,
color: colors.mutedForeground,
),
),
);
}
}
+28
View File
@@ -0,0 +1,28 @@
import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/widgets.dart';
typedef RefreshAction = Future<void> Function();
/// Shared pull-to-refresh and load-more wrapper for future list features.
class AppRefresh extends StatelessWidget {
const AppRefresh({
super.key,
required this.child,
this.onRefresh,
this.onLoad,
this.controller,
});
final Widget child;
final RefreshAction? onRefresh;
final RefreshAction? onLoad;
final EasyRefreshController? controller;
@override
Widget build(BuildContext context) => EasyRefresh(
controller: controller,
onRefresh: onRefresh,
onLoad: onLoad,
child: child,
);
}
+62
View File
@@ -0,0 +1,62 @@
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'app_state_card.dart';
/// Shared loading, failure and empty-state contract for feature pages.
class AsyncStateView<T> extends StatelessWidget {
const AsyncStateView({
super.key,
required this.state,
required this.data,
this.isEmpty,
this.empty,
this.loading,
this.onRetry,
this.errorTitle = '加载失败',
this.errorSubtitle = '请检查网络后重试',
this.emptyIcon = Icons.inbox_outlined,
this.emptyTitle = '暂无内容',
this.emptySubtitle = '暂时没有可展示的数据',
});
final AsyncValue<T> state;
final Widget Function(T value) data;
final bool Function(T value)? isEmpty;
final Widget Function()? empty;
final Widget? loading;
final VoidCallback? onRetry;
final String errorTitle;
final String errorSubtitle;
final IconData emptyIcon;
final String emptyTitle;
final String emptySubtitle;
@override
Widget build(BuildContext context) {
return state.when(
loading: () =>
loading ?? const Center(child: CircularProgressIndicator()),
error: (_, _) => Center(
child: AppStateCard(
icon: Icons.error_outline,
title: errorTitle,
subtitle: errorSubtitle,
buttonLabel: onRetry == null ? null : '重试',
onButtonPressed: onRetry,
buttonStyle: AppStateButtonStyle.filled,
),
),
data: (value) => isEmpty?.call(value) == true
? empty?.call() ??
Center(
child: AppStateCard(
icon: emptyIcon,
title: emptyTitle,
subtitle: emptySubtitle,
),
)
: data(value),
);
}
}
@@ -0,0 +1,25 @@
import 'package:easy_refresh/easy_refresh.dart';
/// Applies one Chinese copy set to every pull-to-refresh/list-load control.
void configureEasyRefreshChineseLocalization() {
EasyRefresh.defaultHeaderBuilder = () => const ClassicHeader(
dragText: '下拉刷新',
armedText: '松开刷新',
readyText: '刷新中...',
processingText: '刷新中...',
processedText: '刷新成功',
noMoreText: '没有更多了',
failedText: '刷新失败',
messageText: '上次更新于 %T',
);
EasyRefresh.defaultFooterBuilder = () => const ClassicFooter(
dragText: '上拉加载',
armedText: '松开加载更多',
readyText: '加载中...',
processingText: '加载中...',
processedText: '加载完成',
noMoreText: '没有更多了',
failedText: '加载失败',
messageText: '上次更新于 %T',
);
}
@@ -0,0 +1,155 @@
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../common/services/device_header_service.dart';
import '../../auth/data/auth_models.dart';
class FeedbackEmailService {
const FeedbackEmailService._();
static const recipient = 'business@yqzhice.top';
static const productName = '金值';
static Future<void> send(AuthState? authState) async {
final email = await _buildEmail(authState);
final uri = composeMailtoUri(
recipient: email.recipient,
subject: email.subject,
body: email.body,
);
try {
final launched = await launchUrl(
uri,
mode: LaunchMode.externalApplication,
);
if (!launched) throw const FeedbackEmailUnavailableException();
} catch (_) {
throw const FeedbackEmailUnavailableException();
}
}
@visibleForTesting
static Uri composeMailtoUri({
required String recipient,
required String subject,
required String body,
}) => Uri(
scheme: 'mailto',
path: recipient,
query: _encodeQueryParameters({'subject': subject, 'body': body}),
);
static String _encodeQueryParameters(
Map<String, String> parameters,
) => parameters.entries
.map(
(entry) =>
'${Uri.encodeComponent(entry.key)}=${Uri.encodeComponent(entry.value)}',
)
.join('&');
static Future<_FeedbackEmail> _buildEmail(AuthState? authState) async {
final packageInfo = await PackageInfo.fromPlatform();
final device = await _loadDeviceInfo();
try {
await DeviceHeaderService.to.ensureInitialized();
} catch (_) {}
final headers = DeviceHeaderService.to.commonHeaders();
final loggedIn = authState is LoggedInAuthState ? authState : null;
final version = '${packageInfo.version}+${packageInfo.buildNumber}';
final diagnostics = [
'App version: $version',
'Channel: ${headers['User-Channel'] ?? ''}',
'OS version: ${device.osVersion}',
'Device manufacturer: ${device.manufacturer}',
'Device model: ${device.model}',
'Login type: ${loggedIn == null ? 'guest' : 'phone'}',
'Phone: ${loggedIn?.user.phone ?? ''}',
].join('\n');
return _FeedbackEmail(
recipient: recipient,
subject:
'$productName反馈[$version]-[${device.manufacturer}]-[${device.osVersion}]',
body: [
'$productName团队你好,',
'请描述你的问题,可附上截图或视频:',
'',
'',
'----',
diagnostics,
].join('\n'),
);
}
static Future<_FeedbackDeviceInfo> _loadDeviceInfo() async {
final plugin = DeviceInfoPlugin();
try {
if (kIsWeb) {
final info = await plugin.webBrowserInfo;
return _FeedbackDeviceInfo(
osVersion: info.platform ?? 'web',
manufacturer: info.browserName.name,
model: info.userAgent ?? '',
);
}
if (defaultTargetPlatform == TargetPlatform.android) {
final info = await plugin.androidInfo;
return _FeedbackDeviceInfo(
osVersion: info.version.release,
manufacturer: info.manufacturer,
model: info.model,
);
}
if (defaultTargetPlatform == TargetPlatform.iOS) {
final info = await plugin.iosInfo;
return _FeedbackDeviceInfo(
osVersion: info.systemVersion,
manufacturer: 'Apple',
model: info.utsname.machine,
);
}
return const _FeedbackDeviceInfo(
osVersion: '',
manufacturer: '',
model: '',
);
} catch (_) {
return const _FeedbackDeviceInfo(
osVersion: '',
manufacturer: '',
model: '',
);
}
}
}
class FeedbackEmailUnavailableException implements Exception {
const FeedbackEmailUnavailableException();
}
class _FeedbackEmail {
const _FeedbackEmail({
required this.recipient,
required this.subject,
required this.body,
});
final String recipient;
final String subject;
final String body;
}
class _FeedbackDeviceInfo {
const _FeedbackDeviceInfo({
required this.osVersion,
required this.manufacturer,
required this.model,
});
final String osVersion;
final String manufacturer;
final String model;
}
@@ -1,6 +1,5 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_remix/flutter_remix.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -20,6 +19,7 @@ import '../../auth/application/auth_controller.dart';
import '../../auth/data/auth_models.dart';
import '../../profile/application/profile_settings_controller.dart';
import '../../profile/data/profile_models.dart';
import '../application/feedback_email_service.dart';
class SettingsPage extends HookConsumerWidget {
const SettingsPage({super.key});
@@ -31,8 +31,6 @@ class SettingsPage extends HookConsumerWidget {
final profileSettings = ref.watch(profileSettingsControllerProvider);
final authAsync = ref.watch(authProvider);
final loggedIn = authAsync.valueOrNull is LoggedInAuthState;
final contactDebugTapCount = useState(0);
final contactLastTapAt = useRef<DateTime?>(null);
return Scaffold(
backgroundColor: cs.background,
@@ -199,21 +197,12 @@ class SettingsPage extends HookConsumerWidget {
_NavRow(
icon: FlutterRemix.mail_line,
label: '联系我们',
trailing: 'business@hnsiderui.cn',
onTap: () {
final now = DateTime.now();
final lastTapAt = contactLastTapAt.value;
if (lastTapAt == null ||
now.difference(lastTapAt) >
const Duration(milliseconds: 500)) {
contactDebugTapCount.value = 0;
}
contactLastTapAt.value = now;
contactDebugTapCount.value += 1;
if (contactDebugTapCount.value >= 10) {
contactDebugTapCount.value = 0;
contactLastTapAt.value = null;
context.push(AppRoutes.debug);
trailing: FeedbackEmailService.recipient,
onTap: () async {
try {
await FeedbackEmailService.send(authAsync.valueOrNull);
} catch (_) {
if (context.mounted) _showFeedbackEmailFailDialog(context);
}
},
),
@@ -337,13 +326,15 @@ class SettingsPage extends HookConsumerWidget {
_ChoiceButton(
label: PriceColorMode.redUpGreenDown.label,
selected: current == PriceColorMode.redUpGreenDown,
onTap: () => Navigator.of(ctx).pop(PriceColorMode.redUpGreenDown),
onTap: () =>
Navigator.of(ctx).pop(PriceColorMode.redUpGreenDown),
),
const SizedBox(height: 12),
_ChoiceButton(
label: PriceColorMode.greenUpRedDown.label,
selected: current == PriceColorMode.greenUpRedDown,
onTap: () => Navigator.of(ctx).pop(PriceColorMode.greenUpRedDown),
onTap: () =>
Navigator.of(ctx).pop(PriceColorMode.greenUpRedDown),
),
],
),
@@ -351,9 +342,9 @@ class SettingsPage extends HookConsumerWidget {
),
);
if (selected != null && context.mounted) {
ref.read(profileSettingsControllerProvider.notifier).setPriceColorMode(
selected,
);
ref
.read(profileSettingsControllerProvider.notifier)
.setPriceColorMode(selected);
}
}
@@ -720,6 +711,24 @@ class SettingsPage extends HookConsumerWidget {
}
}
void _showFeedbackEmailFailDialog(BuildContext context) {
showDialog<void>(
context: context,
builder: (context) => AlertDialog(
title: const Text('无法发送反馈'),
content: const Text(
'请配置并登录系统邮箱,或使用其他邮箱发送邮件至 ${FeedbackEmailService.recipient}。',
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('确定'),
),
],
),
);
}
class _Section extends StatelessWidget {
const _Section(this.title);
@@ -1081,9 +1090,7 @@ class _ChoiceButton extends StatelessWidget {
decoration: BoxDecoration(
color: selected ? cs.primary : cs.secondary,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: selected ? cs.primary : cs.border,
),
border: Border.all(color: selected ? cs.primary : cs.border),
),
child: Text(
label,
@@ -1182,10 +1189,7 @@ class _ValueRow extends StatelessWidget {
style: TextStyle(fontSize: 15, color: cs.foreground),
),
),
Text(
value,
style: TextStyle(fontSize: 13, color: cs.mutedForeground),
),
Text(value, style: TextStyle(fontSize: 13, color: cs.mutedForeground)),
],
);
}
-2
View File
@@ -1,2 +0,0 @@
# Auto detect text files and perform LF normalization
* text=auto
-37
View File
@@ -1,37 +0,0 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "pub"
directory: "/"
schedule:
interval: "daily"
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-minor", "version-update:semver-patch"]
- package-ecosystem: "pub"
directory: "example"
schedule:
interval: "daily"
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-minor", "version-update:semver-patch"]
- package-ecosystem: "gradle"
directory: "android"
schedule:
interval: "daily"
- package-ecosystem: "gradle"
directory: "example/android"
schedule:
interval: "daily"
@@ -1,34 +0,0 @@
name: Flutter build example
on:
workflow_dispatch:
pull_request:
push:
branches:
- main
jobs:
build_android:
name: Build example for Android
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: Install Flutter
uses: subosito/flutter-action@v2
- name: Disable analytics
run: flutter config --no-analytics
- name: Flutter pub get
run: flutter pub get
- name: Flutter build appbundle
run: |
cd example
flutter build appbundle --release
-101
View File
@@ -1,101 +0,0 @@
name: Flutter checks
on:
workflow_dispatch:
pull_request:
push:
branches:
- main
jobs:
check_pub_dependencies:
name: Check dependencies
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: Install Flutter
uses: subosito/flutter-action@v2
- name: Disable analytics
run: flutter config --no-analytics
- name: Flutter pub get
run: flutter pub get
check_formatting:
name: Check formatting
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: Install Flutter
uses: subosito/flutter-action@v2
- name: Disable analytics
run: flutter config --no-analytics
- name: Flutter pub get
run: flutter pub get
- name: Check Dart formatting
run: dart format --line-length 80 --set-exit-if-changed .
analyze:
name: Dart analyze
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: Install Flutter
uses: subosito/flutter-action@v2
- name: Disable analytics
run: flutter config --no-analytics
- name: Flutter pub get
run: flutter pub get
- name: Run Dart analyze
uses: invertase/github-action-dart-analyzer@v3.0.0
test:
name: Flutter test
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: Install Flutter
uses: subosito/flutter-action@v2
- name: Disable analytics
run: flutter config --no-analytics
- name: Flutter pub get
run: flutter pub get
- name: Flutter test
run: flutter test
test_example:
name: Flutter test example
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: Install Flutter
uses: subosito/flutter-action@v2
- name: Disable analytics
run: flutter config --no-analytics
- name: Flutter pub get
run: |
cd example
flutter pub get
- name: Flutter test example
run: |
cd example
flutter test
-18
View File
@@ -1,18 +0,0 @@
name: Pub publish
on:
release:
types: [published]
jobs:
publish:
name: Pub publish
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: Publish
uses: k-paxian/dart-package-publisher@v1.6
with:
credentialJson: ${{ secrets.CREDENTIALS }}
@@ -1,21 +0,0 @@
name: Pub publish dry run
on:
workflow_dispatch:
push:
branches:
- main
jobs:
publish-dry-run:
name: Pub publish dry run
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- name: Publish dry run
uses: k-paxian/dart-package-publisher@v1.6
with:
credentialJson: 'MockCredentialJson'
dryRunOnly: true
-32
View File
@@ -1,32 +0,0 @@
name: Check pub score
on:
workflow_dispatch:
pull_request:
push:
branches:
- main
jobs:
check-score:
name: Check pub score
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
- uses: axel-op/dart-package-analyzer@v3
id: workflow
with:
githubToken: ${{ secrets.GITHUB_TOKEN }}
- name: Check score
env:
TOTAL: ${{ steps.workflow.outputs.total }}
TOTAL_MAX: ${{ steps.workflow.outputs.total_max }}
run: |
MISSING_POINTS=$(( $TOTAL_MAX - $TOTAL ))
if (( MISSING_POINTS > 0 ))
then
echo Score can be improved!
exit 1
fi
-26
View File
@@ -1,26 +0,0 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.packages
build/
-30
View File
@@ -1,30 +0,0 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "a14f74ff3a1cbd521163c5f03d68113d50af93d3"
channel: "stable"
project_type: plugin
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
- platform: android
create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
-103
View File
@@ -1,103 +0,0 @@
## 0.4.0
* Upgrade Android dependencies (Gradle, AGP, Java, Kotlin)
* Widen `flutter_lints` constraints
## 0.3.6
* Return `null` on platforms other than Android, instead of throwing an exception
## 0.3.5
* Maintenance release
* Update `kotlin` and `gradle`
## 0.3.4
* Refactor native code
## 0.3.3
* Add topics to pubspec.yaml
## 0.3.2
* Improve `namespace` fix for `Android Gradle Plugin` versions < 7
## 0.3.1
* Fix `namespace` for `Android Gradle Plugin` versions < 7
## 0.3.0
* Add `namespace` for compatibility with `Android Gradle Plugin 8`
* Update `Gradle` version
## 0.2.0
* Update `Gradle` version
* Update `Android Gradle plugin` version
* Update `Kotlin` version
* Add Gradle wrapper files
* Update `pubspec.lock` of example (`url: "https://pub.dev"`)
## 0.1.3+1
* Improve readme: Add explanation for connection of `Android ID` and signing key
## 0.1.3
* Add building of example app to GitHub workflows
* Remove unneeded code
## 0.1.2
* Add `Flutter test` for example app to workflows
## 0.1.1+1
* Update readme
## 0.1.1
* Update example app dependencies
## 0.1.0
* Rename Android `applicationId`
* Recreate `android` folder from template
## 0.0.8
* Add more GitHub Actions for checking code quality
* Update kotlin_version from 1.6.10 to 1.7.20
* Update gradle from 7.1.2 to 7.3.1
* Add dependabot
## 0.0.7
* Add Google Play information to README.
## 0.0.6
* Lower minimal sdk version to `2.12.0`.
## 0.0.5
* Documentation typo fix.
## 0.0.4
* Small improvements.
## 0.0.3
* Improve example.
## 0.0.2
* Enhance description to get full pub.dev score.
## 0.0.1
* Initial release.
-29
View File
@@ -1,29 +0,0 @@
BSD 3-Clause License
Copyright (c) 2022, Joachim Nohl
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-47
View File
@@ -1,47 +0,0 @@
# android_id
[![Flutter Community: android_id](https://fluttercommunity.dev/_github/header/android_id)](https://github.com/fluttercommunity/community)
![Pub Version](https://img.shields.io/pub/v/android_id)
A Flutter plugin for retrieving the Android ID.
## Getting started
* Add plugin to pubspec.yaml
* Use it in your code (see examples of all methods below)
## Usage
```dart
const _androidIdPlugin = AndroidId();
final String? androidId = await _androidIdPlugin.getId();
```
## Important
Please note that on `Android 8` and above, the `Android ID` is not unique per device, but also per signing key the app was built with:
<blockquote>
On Android 8.0 (API level 26) and higher versions of the platform, a 64-bit number (expressed as a hexadecimal string), <b>unique to each combination of app-signing key, user, and device.</b>
The value may change if a factory reset is performed on the device or if an APK signing key changes.
</blockquote>
[Android API reference](https://developer.android.com/reference/android/provider/Settings.Secure#ANDROID_ID)
[Stack Overflow explanation](https://stackoverflow.com/a/43393373)
## Google Play
Before using this plugin in your app, make sure to follow Google Play guidelines.
For example [here](https://support.google.com/googleplay/android-developer/answer/6048248#zippy=%2Cpersistent-identifiers-including-android-id):
<blockquote>
<b>Persistent identifiers, including Android ID</b>
Use for non-advertising purposes<br>
You can use persistent identifiers as long as you have a [privacy policy](https://support.google.com/googleplay/android-developer/answer/9859455) and handle the data in accordance with the [Developer Distribution Agreement](https://play.google.com/about/developer-distribution-agreement.html#use) and all applicable privacy laws in the areas where you make your app available.
</blockquote>
@@ -1 +0,0 @@
include: package:flutter_lints/flutter.yaml
-9
View File
@@ -1,9 +0,0 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.cxx
-74
View File
@@ -1,74 +0,0 @@
group = "dev.fluttercommunity.android_id"
version = "1.0-SNAPSHOT"
buildscript {
ext.kotlin_version = "2.0.0"
repositories {
google()
mavenCentral()
maven{url'https://repo1.maven.org/maven2/'}
}
dependencies {
classpath("com.android.tools.build:gradle:8.1.4")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
}
}
allprojects {
repositories {
google()
mavenCentral()
maven{url'https://repo1.maven.org/maven2/'}
}
}
apply plugin: "com.android.library"
apply plugin: "kotlin-android"
android {
if (project.android.hasProperty("namespace")) {
namespace = "dev.fluttercommunity.android_id"
}
compileSdk = 34
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
sourceSets {
main.java.srcDirs += "src/main/kotlin"
test.java.srcDirs += "src/test/kotlin"
}
defaultConfig {
minSdk = 21
}
dependencies {
testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.mockito:mockito-core:5.12.0")
}
testOptions {
unitTests.all {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError"
outputs.upToDateWhen {false}
showStandardStreams = true
}
}
}
}
dependencies {
// implementation 'com.umeng.umsdk:common:9.7.7'// 必选
// implementation 'com.umeng.umsdk:asms:1.8.3'// 必选
}
@@ -1 +0,0 @@
rootProject.name = 'android_id'
@@ -1,8 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="dev.fluttercommunity.android_id">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
tools:ignore="ProtectedPermissions" />
</manifest>
@@ -1,279 +0,0 @@
package dev.fluttercommunity.android_id
import android.annotation.SuppressLint
import android.content.ContentResolver
import android.provider.Settings
import androidx.annotation.NonNull
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import android.content.Context
import android.net.wifi.WifiInfo
import android.net.wifi.WifiManager
import android.os.Build
import android.text.TextUtils
import androidx.core.app.ActivityCompat
import java.io.IOException
import java.io.InputStreamReader
import java.io.LineNumberReader
import java.net.NetworkInterface
import java.util.Collections
import java.util.List
import java.util.ArrayList
import java.util.Locale
import android.content.pm.PackageManager
import android.telephony.TelephonyManager
//import com.umeng.commonsdk.UMConfigure
/** AndroidIdPlugin */
class AndroidIdPlugin : FlutterPlugin, MethodCallHandler {
/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var channel: MethodChannel
private lateinit var contentResolver: ContentResolver
private lateinit var context: Context
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
contentResolver = flutterPluginBinding.applicationContext.contentResolver
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "android_id")
channel.setMethodCallHandler(this)
context = flutterPluginBinding.getApplicationContext()
}
override fun onMethodCall(call: MethodCall, result: Result) {
when (call.method) {
"getId" -> {
try {
result.success(getAndroidId())
} catch (e: Exception) {
result.success("")
// result.error("ERROR_GETTING_ID", "Failed to get Android ID", e.localizedMessage)
}
}
"getImei" -> {
try {
result.success(getImei())
} catch (e: Exception) {
result.success("")
// result.error("ERROR_GETTING_ID", "Failed to get Imei ", e.localizedMessage)
}
}
"getMacAddress" -> {
try {
result.success(getMacAddress())
} catch (e: Exception) {
result.success("")
// result.error("ERROR_GETTING_ID", "Failed to get MacAddress", e.localizedMessage)
}
}
// "getOaid" -> {
// try {
// UMConfigure.getOaid(context) { p0 ->
// if (p0 != null) {
// result.success(p0)
// } else {
// result.success("")
// }
// }
// } catch (e: Exception) {
// result.success("")
//// result.error("ERROR_GETTING_ID", "Failed to get MacAddress", e.localizedMessage)
// }
// }
"checkRoot" -> {
try {
result.success(checkRoot())
} catch (e: Exception) {
result.success(false)
// result.error("ERROR_GETTING_ID", "Failed to get MacAddress", e.localizedMessage)
}
}
"checkIsEmulator" -> {
try {
result.success(checkIsEmulator())
} catch (e: Exception) {
result.success(false)
// result.error("ERROR_GETTING_ID", "Failed to get MacAddress", e.localizedMessage)
}
}
else -> result.notImplemented()
}
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
// Fetch the Android ID while suppressing lint warning about hardware IDs
@SuppressLint("HardwareIds")
private fun getAndroidId(): String {
return Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID)
}
private fun getImei(): String? {
val tm: TelephonyManager =
context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
var IMEIStr = ""
if (ActivityCompat.checkSelfPermission(
context,
android.Manifest.permission.READ_PHONE_STATE
) !== PackageManager.PERMISSION_GRANTED
) {
} else {
try {
IMEIStr = tm.getDeviceId()
if (TextUtils.isEmpty(IMEIStr)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
IMEIStr = tm.getImei()
}
}
} catch (e: java.lang.Exception) {
}
}
return IMEIStr
}
private fun getMacAddress(): String? {
var macNo = MacUtil().getMac(context)
return macNo
}
private fun checkRoot(): Boolean {
return false
}
private fun checkIsEmulator(): Boolean {
return false
}
}
class MacUtil {
/**
* Android 6.0 之前(不包括6.0)获取mac地址
* 必须的权限 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
*
* @param context * @return
*/
@SuppressLint("MissingPermission")
fun getMacDefault(context: Context?): String? {
var mac = ""
if (context == null) {
return mac
}
val wifi: WifiManager =
context.getApplicationContext().getSystemService(Context.WIFI_SERVICE) as WifiManager
var info: WifiInfo? = null
try {
info = wifi.getConnectionInfo()
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
if (info == null) {
return null
}
mac = info.getMacAddress()
if (!TextUtils.isEmpty(mac)) {
mac = mac.uppercase()
}
return mac
}
val macAddress: String?
/**
* Android 6.0-Android 7.0 获取mac地址
*/
get() {
var macSerial: String? = null
var str = ""
try {
val pp: java.lang.Process =
java.lang.Runtime.getRuntime().exec("cat/sys/class/net/wlan0/address")
val ir: InputStreamReader = InputStreamReader(pp.getInputStream())
val input: LineNumberReader = LineNumberReader(ir)
while (null != str) {
str = input.readLine()
if (str != null) {
macSerial = str.trim { it <= ' ' } //去空格
break
}
}
} catch (ex: IOException) {
// 赋予默认值
ex.printStackTrace()
}
return macSerial
}
/**
* 获取mac地址(适配所有Android版本)
*
* @return
*/
fun getMac(context: Context?): String? {
var mac: String? = ""
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
mac = getMacDefault(context)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
mac = macAddress
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mac = macFromHardware
}
return mac
}
companion object {
private val macFromHardware: String?
/**
* Android 7.0之后获取Mac地址
* 遍历循环所有的网络接口,找到接口是 wlan0
* 必须的权限 <uses-permission android:name="android.permission.INTERNET"></uses-permission>
*
* @return
*/
get() {
try {
val all: ArrayList<NetworkInterface> =
Collections.list<NetworkInterface>(NetworkInterface.getNetworkInterfaces())
for (nif in all) {
if (!nif.getName().equals("wlan0", ignoreCase = true)) {
continue
}
val macBytes: ByteArray = nif.getHardwareAddress() ?: return null
val res1: java.lang.StringBuilder = java.lang.StringBuilder()
for (b in macBytes) {
res1.append(String.format("%02X:", b))
}
if (res1.length > 0) {
res1.deleteCharAt(res1.length - 1)
}
return res1.toString()
}
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
return null
}
}
}
-58
View File
@@ -1,58 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
/// The plugin class for retrieving the Android ID.
class AndroidId {
const AndroidId();
/// The method channel used to interact with the native platform.
static const _methodChannel = MethodChannel('android_id');
/// Calls the native method to retrieve the Android ID.
Future<String?> getId() async {
final isAndroid =
!kIsWeb && defaultTargetPlatform == TargetPlatform.android;
if (!isAndroid) return null;
return _methodChannel.invokeMethod<String?>('getId');
}
Future<String?> getImei() async {
final isAndroid =
!kIsWeb && defaultTargetPlatform == TargetPlatform.android;
if (!isAndroid) return null;
return _methodChannel.invokeMethod<String?>('getImei');
}
Future<String?> getMaAddress() async {
final isAndroid =
!kIsWeb && defaultTargetPlatform == TargetPlatform.android;
if (!isAndroid) return null;
return _methodChannel.invokeMethod<String?>('getMacAddress');
}
// Future<String?> getOaid() async {
// final isAndroid =
// !kIsWeb && defaultTargetPlatform == TargetPlatform.android;
// if (!isAndroid) return null;
//
// return _methodChannel.invokeMethod<String?>('getOaid');
// }
Future<bool?> isRoot() async {
final isAndroid =
!kIsWeb && defaultTargetPlatform == TargetPlatform.android;
if (!isAndroid) return null;
return _methodChannel.invokeMethod<bool?>('checkRoot');
}
Future<bool?> isEmulator() async {
final isAndroid =
!kIsWeb && defaultTargetPlatform == TargetPlatform.android;
if (!isAndroid) return null;
return _methodChannel.invokeMethod<bool?>('checkIsEmulator');
}
}
-36
View File
@@ -1,36 +0,0 @@
name: android_id
description: A Flutter plugin for getting the Android ID. Only for Android.
repository: https://github.com/fluttercommunity/android_id
issue_tracker: https://github.com/fluttercommunity/android_id/issues
maintainer: Joachim Nohl (@nohli)
topics:
- androidid
- device
- identifier
- android
- native
version: 0.4.0
environment:
sdk: '>=2.12.0 <4.0.0'
flutter: '>=2.0.0'
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_lints: '>=2.0.0 <4.0.0'
flutter_test:
sdk: flutter
flutter:
plugin:
platforms:
android:
package: dev.fluttercommunity.android_id
pluginClass: AndroidIdPlugin
@@ -1,26 +0,0 @@
import 'package:android_id/android_id.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
const plugin = AndroidId();
const channel = MethodChannel('android_id');
TestWidgetsFlutterBinding.ensureInitialized();
debugDefaultTargetPlatformOverride = TargetPlatform.android;
setUp(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, (methodCall) async => '42');
});
tearDown(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, null);
});
test('getAndroidId', () async {
expect(await plugin.getId(), '42');
});
}
-26
View File
@@ -1,26 +0,0 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.packages
build/
-3
View File
@@ -1,3 +0,0 @@
## 0.0.1
* Initial release.
-29
View File
@@ -1,29 +0,0 @@
BSD 3-Clause License
Copyright (c) 2022, Joachim Nohl
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-15
View File
@@ -1,15 +0,0 @@
# flutter_oaid
A new Flutter plugin project.
## Getting Started
This project is a starting point for a Flutter
[plug-in package](https://flutter.dev/developing-packages/),
a specialized package that includes platform-specific implementation code for
Android and/or iOS.
For help getting started with Flutter development, view the
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
@@ -1 +0,0 @@
include: package:flutter_lints/flutter.yaml
-9
View File
@@ -1,9 +0,0 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.cxx
@@ -1,74 +0,0 @@
group = "dev.fluttercommunity.android_oaid"
version = "1.0-SNAPSHOT"
buildscript {
ext.kotlin_version = "2.0.0"
repositories {
google()
mavenCentral()
maven{url'https://repo1.maven.org/maven2/'}
}
dependencies {
classpath("com.android.tools.build:gradle:8.1.4")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
}
}
allprojects {
repositories {
google()
mavenCentral()
maven{url'https://repo1.maven.org/maven2/'}
}
}
apply plugin: "com.android.library"
apply plugin: "kotlin-android"
android {
if (project.android.hasProperty("namespace")) {
namespace = "dev.fluttercommunity.android_oaid"
}
compileSdk = 34
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
sourceSets {
main.java.srcDirs += "src/main/kotlin"
test.java.srcDirs += "src/test/kotlin"
}
defaultConfig {
minSdk = 21
}
dependencies {
testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.mockito:mockito-core:5.12.0")
}
testOptions {
unitTests.all {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError"
outputs.upToDateWhen {false}
showStandardStreams = true
}
}
}
}
dependencies {
implementation 'com.umeng.umsdk:common:9.7.7'// 必选
implementation 'com.umeng.umsdk:asms:1.8.3'// 必选
}
@@ -1 +0,0 @@
rootProject.name = 'android_oaid'
@@ -1,5 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="dev.fluttercommunity.android_oaid">
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
@@ -1,59 +0,0 @@
package dev.fluttercommunity.android_oaid
import android.content.ContentResolver
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import android.content.Context
import android.os.Handler
import android.os.Looper
import com.umeng.commonsdk.UMConfigure
/** AndroidOaidPlugin */
class AndroidOaidPlugin : FlutterPlugin, MethodCallHandler {
private lateinit var channel: MethodChannel
private lateinit var contentResolver: ContentResolver
private lateinit var context: Context
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
contentResolver = flutterPluginBinding.applicationContext.contentResolver
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "android_oaid")
channel.setMethodCallHandler(this)
context = flutterPluginBinding.getApplicationContext()
}
override fun onMethodCall(call: MethodCall, result: Result) {
when (call.method) {
"getOaid" -> {
try {
UMConfigure.getOaid(context) { p0 ->
Handler(Looper.getMainLooper()).post {
if (p0 != null) {
result.success(p0)
} else {
result.success("")
}
}
}
} catch (e: Exception) {
Handler(Looper.getMainLooper()).post {
result.success("")
}
}
}
else -> result.notImplemented()
}
}
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}
}
@@ -1,18 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
class AndroidOaidId {
const AndroidOaidId();
static const _methodChannel = MethodChannel('android_oaid');
Future<String?> getOaid() async {
final isAndroid =
!kIsWeb && defaultTargetPlatform == TargetPlatform.android;
if (!isAndroid) return null;
return _methodChannel.invokeMethod<String?>('getOaid');
}
}
-26
View File
@@ -1,26 +0,0 @@
name: android_oaid
description: A Flutter plugin for getting the Android OAID. Only for Android.
maintainer: Joachim Nohl (@nohli)
version: 0.4.0
environment:
sdk: '>=2.12.0 <4.0.0'
flutter: '>=2.0.0'
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_lints: '>=2.0.0 <4.0.0'
flutter_test:
sdk: flutter
flutter:
plugin:
platforms:
android:
package: dev.fluttercommunity.android_oaid
pluginClass: AndroidOaidPlugin
@@ -1,26 +0,0 @@
import 'package:android_oaid/android_oaid.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
const plugin = AndroidOaidId();
const channel = MethodChannel('android_oaid');
TestWidgetsFlutterBinding.ensureInitialized();
debugDefaultTargetPlatformOverride = TargetPlatform.android;
setUp(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, (methodCall) async => '42');
});
tearDown(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, null);
});
test('getAndroidId', () async {
expect(await plugin.getOaid(), '42');
});
}
-29
View File
@@ -1,29 +0,0 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
build/
-30
View File
@@ -1,30 +0,0 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "abb292a07e20d696c4568099f918f6c5f330e6b0"
channel: "stable"
project_type: plugin
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0
base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0
- platform: ios
create_revision: abb292a07e20d696c4568099f918f6c5f330e6b0
base_revision: abb292a07e20d696c4568099f918f6c5f330e6b0
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
-3
View File
@@ -1,3 +0,0 @@
## 0.0.1
* TODO: Describe initial release.
-1
View File
@@ -1 +0,0 @@
TODO: Add your license here.
-15
View File
@@ -1,15 +0,0 @@
# flutter_paid
A new Flutter plugin project.
## Getting Started
This project is a starting point for a Flutter
[plug-in package](https://flutter.dev/developing-packages/),
a specialized package that includes platform-specific implementation code for
Android and/or iOS.
For help getting started with Flutter development, view the
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
@@ -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
-43
View File
@@ -1,43 +0,0 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
-16
View File
@@ -1,16 +0,0 @@
# flutter_paid_example
Demonstrates how to use the flutter_paid 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://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
@@ -1,28 +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.dev/lints.
#
# 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
@@ -1,25 +0,0 @@
// This is a basic Flutter integration test.
//
// Since integration tests run in a full Flutter application, they can interact
// with the host side of a plugin implementation, unlike Dart unit tests.
//
// For more information about Flutter integration tests, please see
// https://docs.flutter.dev/cookbook/testing/integration/introduction
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:flutter_paid/flutter_paid.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('getPlatformVersion test', (WidgetTester tester) async {
final FlutterPaid plugin = FlutterPaid();
final String? version = await plugin.getPlatformVersion();
// The version string depends on the host platform running the test, so
// just assert that some non-empty string is returned.
expect(version?.isNotEmpty, true);
});
}
@@ -1,34 +0,0 @@
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3
@@ -1,26 +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>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
</dict>
</plist>
@@ -1,2 +0,0 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
@@ -1,2 +0,0 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
-41
View File
@@ -1,41 +0,0 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '12.0'
# 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', '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 Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end
@@ -1,28 +0,0 @@
PODS:
- Flutter (1.0.0)
- flutter_paid (0.0.1):
- Flutter
- integration_test (0.0.1):
- Flutter
DEPENDENCIES:
- Flutter (from `Flutter`)
- flutter_paid (from `.symlinks/plugins/flutter_paid/ios`)
- integration_test (from `.symlinks/plugins/integration_test/ios`)
EXTERNAL SOURCES:
Flutter:
:path: Flutter
flutter_paid:
:path: ".symlinks/plugins/flutter_paid/ios"
integration_test:
:path: ".symlinks/plugins/integration_test/ios"
SPEC CHECKSUMS:
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_paid: 4461d2236314bded6afb221cd9d69b7f7ca51fc6
integration_test: 13825b8a9334a850581300559b8839134b124670
PODFILE CHECKSUM: 6e700dec67e6deac9b1c69bb14c49a2217a12d15
COCOAPODS: 1.14.3
@@ -1,704 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
1200A014D953763B34535EB3 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CB8157ECFBC61BAC8F6DDD98 /* libPods-Runner.a */; };
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C80F4294D02FB00263BE5 /* RunnerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 331C80F3294D02FB00263BE5 /* RunnerTests.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74D02B72575A8C8A1492AE70 /* libPods-RunnerTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BF91C3F82401F1EC86B8BDBB /* libPods-RunnerTests.a */; };
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
331C80F5294D02FB00263BE5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
remoteInfo = Runner;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0733CEEBA4D517AC13DB7032 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
331C80F1294D02FB00263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
331C80F3294D02FB00263BE5 /* RunnerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RunnerTests.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
AA2F596DEE97CE584753926C /* 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>"; };
BF91C3F82401F1EC86B8BDBB /* libPods-RunnerTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RunnerTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
C4F40650D87222AA05FBB409 /* 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>"; };
CB8157ECFBC61BAC8F6DDD98 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
DB6D020E7BD00B83208B9A03 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
F5AC35C52992172B47892D71 /* 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>"; };
F606F420C75B7A999C3003F1 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
331C80EE294D02FB00263BE5 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
74D02B72575A8C8A1492AE70 /* libPods-RunnerTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
1200A014D953763B34535EB3 /* libPods-Runner.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
331C80F2294D02FB00263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C80F3294D02FB00263BE5 /* RunnerTests.m */,
);
path = RunnerTests;
sourceTree = "<group>";
};
3D1BD31C0A91C924BAF12C36 /* Frameworks */ = {
isa = PBXGroup;
children = (
CB8157ECFBC61BAC8F6DDD98 /* libPods-Runner.a */,
BF91C3F82401F1EC86B8BDBB /* libPods-RunnerTests.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
331C80F2294D02FB00263BE5 /* RunnerTests */,
97C146EF1CF9000F007C117D /* Products */,
F4667D52B031A4D8AAF7780D /* Pods */,
3D1BD31C0A91C924BAF12C36 /* Frameworks */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
331C80F1294D02FB00263BE5 /* RunnerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
97C146F11CF9000F007C117D /* Supporting Files */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
);
path = Runner;
sourceTree = "<group>";
};
97C146F11CF9000F007C117D /* Supporting Files */ = {
isa = PBXGroup;
children = (
97C146F21CF9000F007C117D /* main.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
F4667D52B031A4D8AAF7780D /* Pods */ = {
isa = PBXGroup;
children = (
C4F40650D87222AA05FBB409 /* Pods-Runner.debug.xcconfig */,
AA2F596DEE97CE584753926C /* Pods-Runner.release.xcconfig */,
F5AC35C52992172B47892D71 /* Pods-Runner.profile.xcconfig */,
DB6D020E7BD00B83208B9A03 /* Pods-RunnerTests.debug.xcconfig */,
F606F420C75B7A999C3003F1 /* Pods-RunnerTests.release.xcconfig */,
0733CEEBA4D517AC13DB7032 /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
331C80F0294D02FB00263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C80F7294D02FB00263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
AFF8B152CD6A1DD5D70EC498 /* [CP] Check Pods Manifest.lock */,
331C80ED294D02FB00263BE5 /* Sources */,
331C80EE294D02FB00263BE5 /* Frameworks */,
331C80EF294D02FB00263BE5 /* Resources */,
);
buildRules = (
);
dependencies = (
331C80F6294D02FB00263BE5 /* PBXTargetDependency */,
);
name = RunnerTests;
productName = RunnerTests;
productReference = 331C80F1294D02FB00263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
99BA78E65A21CE04C8370CA7 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C80F0294D02FB00263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 97C146ED1CF9000F007C117D;
};
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
331C80F0294D02FB00263BE5 /* RunnerTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
331C80EF294D02FB00263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
99BA78E65A21CE04C8370CA7 /* [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;
};
AFF8B152CD6A1DD5D70EC498 /* [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-RunnerTests-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 */
331C80ED294D02FB00263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C80F4294D02FB00263BE5 /* RunnerTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
97C146F31CF9000F007C117D /* main.m in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C80F6294D02FB00263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 97C146ED1CF9000F007C117D /* Runner */;
targetProxy = 331C80F5294D02FB00263BE5 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
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_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
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_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 979UK3QQJ3;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterPaidExample;
PRODUCT_NAME = "$(TARGET_NAME)";
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
331C80F8294D02FB00263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = DB6D020E7BD00B83208B9A03 /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterPaidExample.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Debug;
};
331C80F9294D02FB00263BE5 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = F606F420C75B7A999C3003F1 /* Pods-RunnerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterPaidExample.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Release;
};
331C80FA294D02FB00263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 0733CEEBA4D517AC13DB7032 /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterPaidExample.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
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_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
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_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
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_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
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_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
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_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 979UK3QQJ3;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterPaidExample;
PRODUCT_NAME = "$(TARGET_NAME)";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 979UK3QQJ3;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterPaidExample;
PRODUCT_NAME = "$(TARGET_NAME)";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
331C80F7294D02FB00263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C80F8294D02FB00263BE5 /* Debug */,
331C80F9294D02FB00263BE5 /* Release */,
331C80FA294D02FB00263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
@@ -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>
@@ -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>PreviewsEnabled</key>
<false/>
</dict>
</plist>
@@ -1,98 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.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 = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C80F0294D02FB00263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</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 = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.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 = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -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>
@@ -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>
@@ -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>PreviewsEnabled</key>
<false/>
</dict>
</plist>
@@ -1,6 +0,0 @@
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : FlutterAppDelegate
@end
@@ -1,13 +0,0 @@
#import "AppDelegate.h"
#import "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
@@ -1,122 +0,0 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 762 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Loaded 100 of 133 files, more files were not shown because too many files have changed in this diff. Show more