初始化
@@ -0,0 +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>
|
||||
@@ -0,0 +1,318 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.xvproject">
|
||||
|
||||
<!-- release 包只用 main manifest,INTERNET 必须在这里声明;
|
||||
否则 release 无网络权限,启动选线 host lookup errno=7,弹"线路检测失败" -->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<application
|
||||
android:label="黄果短剧"
|
||||
android:name=".JPApplication"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:largeHeap="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:extractNativeLibs="true"
|
||||
android:requestLegacyExternalStorage="true">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity-alias
|
||||
android:name=".lld"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="黄果短剧"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".aiyinyue"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="爱音乐"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_1"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
|
||||
<activity-alias
|
||||
android:name=".aiyuedu"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="爱阅读"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_2"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".alipay"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="支付宝"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_3"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".bilibili"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="哔哩哔哩"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_4"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".binggandazhuozhan"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="金铲铲之战"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_5"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".meisijiejian"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="美食借鉴"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_6"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".myworld"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="我的世界"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_7"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
|
||||
<activity-alias
|
||||
android:name=".shenxuanzhizhan"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="神选之战"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_8"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
|
||||
<activity-alias
|
||||
android:name=".shuixinwuxian"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="随心无线"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_9"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
|
||||
<activity-alias
|
||||
android:name=".texuanxiaoshuo"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="特轩小说"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_10"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".tiantianmajiang"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="天天麻将"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_11"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".tuyou"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="途游"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_12"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".weichat"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="微信"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_13"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".wendao"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="问道"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_14"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".yinyutusujiao"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="英语图书角"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_15"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".icon_16"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="91PO黄果短剧RN"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_16"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".icon_17"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="黄果短剧"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_17"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".icon_18"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:label="黄果短剧"
|
||||
android:enabled="false"
|
||||
android:icon="@mipmap/icon_18"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true"
|
||||
tools:replace="android:authorities">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/totalfilepath"
|
||||
tools:replace="android:resource" />
|
||||
</provider>
|
||||
|
||||
<provider
|
||||
android:name="com.pichillilorenzo.flutter_inappwebview_android.InAppWebViewFileProvider"
|
||||
android:authorities="${applicationId}.flutter_inappwebview_android.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/provider_paths" />
|
||||
</provider>
|
||||
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,104 @@
|
||||
package io.flutter.plugins;
|
||||
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
|
||||
/// 本地视频文件信息:时长 / 分辨率 / 比例 / 高度 / 比特率
|
||||
/// 注:MediaMetadataRetriever 持有 native 资源,每次用完必须 release,否则多次调用后取不到任何信息
|
||||
public class JPFileUtils {
|
||||
|
||||
/**
|
||||
* 获取视频时长(秒)
|
||||
*/
|
||||
public static int getVideoDuration(String filePath) {
|
||||
String ms = extract(filePath, MediaMetadataRetriever.METADATA_KEY_DURATION);
|
||||
if (TextUtils.isEmpty(ms) || !TextUtils.isDigitsOnly(ms)) return 0;
|
||||
return Integer.parseInt(ms) / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取视频分辨率,格式 "宽*高",取不到返回空串
|
||||
*/
|
||||
public static String getVideoResolution(String filePath) {
|
||||
int[] size = videoSize(filePath);
|
||||
return size[0] > 0 && size[1] > 0 ? size[0] + "*" + size[1] : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取视频宽高比
|
||||
*/
|
||||
public static String getVideoRatio(String filePath) {
|
||||
int[] size = videoSize(filePath);
|
||||
if (size[0] <= 0 || size[1] <= 0) return "0";
|
||||
return String.valueOf((float) size[0] / size[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取视频高度
|
||||
*/
|
||||
public static String getVideoHeight(String filePath) {
|
||||
int[] size = videoSize(filePath);
|
||||
if (size[0] <= 0 || size[1] <= 0) return "0";
|
||||
return String.valueOf(size[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取比特率
|
||||
*/
|
||||
public static String getVideoBitrate(String filePath) {
|
||||
String bitrate = extract(filePath, MediaMetadataRetriever.METADATA_KEY_BITRATE);
|
||||
return TextUtils.isEmpty(bitrate) ? "0" : bitrate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取单个 metadata;用 FD 而非路径设源,避开部分机型对中文/特殊字符路径的兼容问题
|
||||
*/
|
||||
private static String extract(String filePath, int key) {
|
||||
if (TextUtils.isEmpty(filePath)) return null;
|
||||
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
|
||||
try (FileInputStream in = new FileInputStream(filePath)) {
|
||||
mmr.setDataSource(in.getFD());
|
||||
return mmr.extractMetadata(key);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
} finally {
|
||||
release(mmr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频宽高,取不到返回 {0,0}。宽高一次打开取完,避免为了宽和高开两次文件
|
||||
*/
|
||||
private static int[] videoSize(String filePath) {
|
||||
int[] empty = {0, 0};
|
||||
if (TextUtils.isEmpty(filePath)) return empty;
|
||||
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
|
||||
try (FileInputStream in = new FileInputStream(filePath)) {
|
||||
mmr.setDataSource(in.getFD());
|
||||
int width = parseInt(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH));
|
||||
int height = parseInt(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT));
|
||||
return new int[]{width, height};
|
||||
} catch (Exception e) {
|
||||
return empty;
|
||||
} finally {
|
||||
release(mmr);
|
||||
}
|
||||
}
|
||||
|
||||
private static int parseInt(String value) {
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
} catch (Exception e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static void release(MediaMetadataRetriever mmr) {
|
||||
try {
|
||||
mmr.release();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package io.flutter.plugins;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.media.MediaCodecInfo;
|
||||
import android.media.MediaCodecList;
|
||||
import android.media.MediaFormat;
|
||||
import android.os.Build;
|
||||
|
||||
import com.meituan.android.walle.WalleChannelReader;
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity;
|
||||
import io.flutter.embedding.engine.FlutterEngine;
|
||||
import io.flutter.plugin.common.MethodCall;
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
|
||||
/// 本地插件:设备号 / 视频文件信息 / 渠道号 / H265 硬解能力
|
||||
public class JPNativePlugin implements MethodChannel.MethodCallHandler {
|
||||
|
||||
private static final String CHANNEL = "com.yinse/device";
|
||||
|
||||
private final Activity activity;
|
||||
|
||||
private JPNativePlugin(Activity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
/// 注册
|
||||
public static void registerWith(FlutterActivity flutterActivity, FlutterEngine engine) {
|
||||
MethodChannel channel = new MethodChannel(engine.getDartExecutor().getBinaryMessenger(), CHANNEL);
|
||||
channel.setMethodCallHandler(new JPNativePlugin(flutterActivity));
|
||||
}
|
||||
|
||||
/// 调用
|
||||
@Override
|
||||
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
|
||||
switch (call.method) {
|
||||
case "getVideoDuration":
|
||||
result.success(JPFileUtils.getVideoDuration(call.argument("filePath")));
|
||||
break;
|
||||
case "getVideoResolution":
|
||||
result.success(JPFileUtils.getVideoResolution(call.argument("filePath")));
|
||||
break;
|
||||
case "getVideoRatio":
|
||||
result.success(JPFileUtils.getVideoRatio(call.argument("filePath")));
|
||||
break;
|
||||
case "getVideoHeight":
|
||||
result.success(JPFileUtils.getVideoHeight(call.argument("filePath")));
|
||||
break;
|
||||
case "getVideoBitrate":
|
||||
result.success(JPFileUtils.getVideoBitrate(call.argument("filePath")));
|
||||
break;
|
||||
case "getChannel": // 获取android 渠道的东西
|
||||
result.success(getChannel(activity));
|
||||
break;
|
||||
case "isH265HardwareSupported":
|
||||
result.success(isHevcHardwareSupported());
|
||||
break;
|
||||
default:
|
||||
// 不回 result 的话 Dart 那边的 Future 永远不完成
|
||||
result.notImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取渠道号
|
||||
public static String getChannel(Context context) {
|
||||
return WalleChannelReader.getChannel(context);
|
||||
}
|
||||
|
||||
/// 本机是否**硬解** H.265(HEVC)。只认硬解:软解(google/c2.android)当不支持,回落 264。
|
||||
/// 查询编解码器能力,任何异常都按不支持处理。
|
||||
private static boolean isHevcHardwareSupported() {
|
||||
try {
|
||||
MediaCodecList list = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
|
||||
for (MediaCodecInfo info : list.getCodecInfos()) {
|
||||
if (info.isEncoder() || !supportsHevc(info)) continue;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
if (info.isHardwareAccelerated()) return true; // API29+ 直接问硬解
|
||||
} else {
|
||||
String name = info.getName().toLowerCase(); // 旧版本靠名字排除软解
|
||||
if (!name.startsWith("omx.google.") && !name.startsWith("c2.android.")) return true;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean supportsHevc(MediaCodecInfo info) {
|
||||
for (String type : info.getSupportedTypes()) {
|
||||
if (type.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.xvproject
|
||||
|
||||
import io.flutter.app.FlutterApplication
|
||||
|
||||
class JPApplication : FlutterApplication()
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.xvproject
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.ActivityManager
|
||||
import android.content.ComponentName
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugins.JPNativePlugin
|
||||
|
||||
class MainActivity : FlutterActivity() {
|
||||
|
||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||
super.configureFlutterEngine(flutterEngine)
|
||||
JPNativePlugin.registerWith(this, flutterEngine)
|
||||
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
|
||||
.setMethodCallHandler { call, result ->
|
||||
when (call.method) {
|
||||
METHOD_CHANGE_ICON -> {
|
||||
val index = call.argument<Int>(ARG_ICON_INDEX) ?: -1
|
||||
ICON_ALIASES.getOrNull(index)?.let { switchIcon("$ALIAS_PACKAGE.$it") }
|
||||
result.success(true)
|
||||
}
|
||||
// 不回 result 的话 Dart 那边的 Future 永远不完成
|
||||
else -> result.notImplemented()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 切换启动图标:禁用当前入口 + 启用目标 alias,再杀掉桌面进程让图标立刻刷新
|
||||
private fun switchIcon(alias: String) {
|
||||
val pm = packageManager
|
||||
pm.setComponentEnabledSetting(
|
||||
componentName,
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP
|
||||
)
|
||||
pm.setComponentEnabledSetting(
|
||||
ComponentName(this, alias),
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP
|
||||
)
|
||||
restartLauncher(pm)
|
||||
}
|
||||
|
||||
/// 杀掉桌面进程,强制它重读图标
|
||||
@SuppressLint("ServiceCast")
|
||||
private fun restartLauncher(pm: PackageManager) {
|
||||
val am = getSystemService(ACTIVITY_SERVICE) as ActivityManager
|
||||
val intent = Intent(Intent.ACTION_MAIN)
|
||||
.addCategory(Intent.CATEGORY_HOME)
|
||||
.addCategory(Intent.CATEGORY_DEFAULT)
|
||||
for (info in pm.queryIntentActivities(intent, 0)) {
|
||||
am.killBackgroundProcesses(info.activityInfo?.packageName ?: continue)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
//这个跟flutter的通道名称保持一致
|
||||
private const val CHANNEL = "com.yinse/request"
|
||||
|
||||
private const val METHOD_CHANGE_ICON = "changeIcon"
|
||||
private const val ARG_ICON_INDEX = "iconIndex"
|
||||
|
||||
/// 图标 alias 所在包名:AndroidManifest 里 activity-alias 写的是相对名(manifest package=com.xvproject),
|
||||
/// 与 applicationId 不同,不能用 packageName 拼
|
||||
private const val ALIAS_PACKAGE = "com.xvproject"
|
||||
|
||||
/// 下标即 Flutter 传来的 iconIndex,顺序必须与 manifest 里 activity-alias 的声明顺序一致
|
||||
private val ICON_ALIASES = listOf(
|
||||
"lld", "aiyinyue", "aiyuedu", "alipay", "bilibili", "binggandazhuozhan",
|
||||
"meisijiejian", "myworld", "shenxuanzhizhan", "shuixinwuxian", "texuanxiaoshuo",
|
||||
"tiantianmajiang", "tuyou", "weichat", "wendao", "yinyutusujiao",
|
||||
"icon_16", "icon_17", "icon_18", //清明 / 端午 / 劳动
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="?android:colorBackground" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector
|
||||
android:height="108dp"
|
||||
android:width="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/white" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:opacity="opaque">
|
||||
<item android:gravity="center">
|
||||
<bitmap
|
||||
android:gravity="center_horizontal"
|
||||
android:mipMap="true"
|
||||
android:src="@mipmap/ic_splash_bg" />
|
||||
</item>
|
||||
|
||||
</layer-list>
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 208 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">@drawable/launch_bg</item>
|
||||
<item name="android:colorPrimary">#12131C</item>
|
||||
<item name="colorPrimaryDark">#12131C</item>
|
||||
<item name="colorAccent">#12131C</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
</style>
|
||||
<!-- Flutter UI 初始化时及运行时的窗口背景;缺失会导致浅色模式下窗口透明 -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<paths>
|
||||
<external-path
|
||||
name="external-path"
|
||||
path="." />
|
||||
<external-cache-path
|
||||
name="external-cache-path"
|
||||
path="." />
|
||||
<external-files-path
|
||||
name="external-files-path"
|
||||
path="." />
|
||||
<files-path
|
||||
name="files_path"
|
||||
path="." />
|
||||
<cache-path
|
||||
name="cache-path"
|
||||
path="." />
|
||||
<root-path
|
||||
name="name"
|
||||
path="." />
|
||||
<external-path
|
||||
name="external_storage_root"
|
||||
path="." />
|
||||
</paths>
|
||||
@@ -0,0 +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>
|
||||