Compare commits
5 Commits
e3fdac7bb0
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| da64066a21 | |||
| 00791f1021 | |||
| bce9cac658 | |||
| cde179becc | |||
| 759a262658 |
8
.idea/deploymentTargetSelector.xml
generated
8
.idea/deploymentTargetSelector.xml
generated
@@ -446,6 +446,14 @@
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
<DialogSelection />
|
||||
</SelectionState>
|
||||
<SelectionState runConfigName="titanplayz">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
<DialogSelection />
|
||||
</SelectionState>
|
||||
<SelectionState runConfigName="amazy">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
<DialogSelection />
|
||||
</SelectionState>
|
||||
</selectionStates>
|
||||
</component>
|
||||
</project>
|
||||
2
.idea/gradle.xml
generated
2
.idea/gradle.xml
generated
@@ -30,6 +30,7 @@
|
||||
<option value="$PROJECT_DIR$/aa7au" />
|
||||
<option value="$PROJECT_DIR$/afb77au" />
|
||||
<option value="$PROJECT_DIR$/aipokies" />
|
||||
<option value="$PROJECT_DIR$/amazy" />
|
||||
<option value="$PROJECT_DIR$/aud2u26" />
|
||||
<option value="$PROJECT_DIR$/auplayx" />
|
||||
<option value="$PROJECT_DIR$/b88" />
|
||||
@@ -80,6 +81,7 @@
|
||||
<option value="$PROJECT_DIR$/slotkaki33" />
|
||||
<option value="$PROJECT_DIR$/telur33" />
|
||||
<option value="$PROJECT_DIR$/test" />
|
||||
<option value="$PROJECT_DIR$/titanplayz" />
|
||||
<option value="$PROJECT_DIR$/toke66a" />
|
||||
<option value="$PROJECT_DIR$/u8888aud" />
|
||||
<option value="$PROJECT_DIR$/uu3au" />
|
||||
|
||||
50
README.md
50
README.md
@@ -1,5 +1,46 @@
|
||||
# 封装APP 版本迭代
|
||||
|
||||
# 历史更新补充
|
||||
以下记录根据 Git 历史按功能阶段归纳。部分 APP 使用独立的 versionName/versionCode,具体版本号以各模块 build.gradle 为准。
|
||||
|
||||
# V1.3.9 后续维护 2026年8月4日 start 完善站点用户信息采集
|
||||
支持遍历网页 localStorage 中多个候选用户缓存。
|
||||
每个有效用户对象单独调用 /api/client/user-info 上报。
|
||||
按手机号进行本地去重,同一手机号只重复提交一次。
|
||||
单个用户上报失败时只清理该用户的重试标识,不影响其他用户。
|
||||
保留用户对象完整字段,仅过滤 bonus、gameAccess、time、timebonus、rollover、banks。
|
||||
|
||||
# V1.3.9 后续维护 2026年7月31日 start 通知和站点用户采集
|
||||
新增通知列表、通知详情和通知阅读处理。
|
||||
新增站点用户信息首次采集接口,绑定 userId、站点域名和设备类型。
|
||||
增加用户信息 JSON 校验、手机号必填校验和重复手机号处理。
|
||||
新增 amazy、titanplayz 等 APP 模块的基础配置和推送资源。
|
||||
|
||||
# V1.3.9 后续维护 2026年7月30日 start 系统适配和模块扩展
|
||||
修复部分设备满屏显示问题。
|
||||
优化状态栏、导航栏和系统窗口 Insets 适配。
|
||||
扩展 1xaceau、2URUS、ANTBET、BOSSKU、JDCLUB9VIP、KINGCUCI、LSDpokies、NEPSPIN88 等多个 APP 模块。
|
||||
统一新模块的 Firebase、签名文件、应用图标和基础主题配置。
|
||||
|
||||
# V1.3.9 后续维护 2026年6月23日—2026年7月23日 start 工程和发布维护
|
||||
新增 2U8OB 模块。
|
||||
更新多个模块的部署目标和工程配置。
|
||||
停止跟踪生成的 APK 文件,减少仓库中的构建产物。
|
||||
|
||||
# V1.3.9 2026年5月18日 start 版本和功能整理
|
||||
统一部分 APP 的版本号和应用名称配置。
|
||||
更新 bb8au、xoxau、sg99live 等模块的版本、用户 ID 和资源文件。
|
||||
新增 bng33、pokiesplay、nep9 等 APP 模块。
|
||||
新增通讯录权限申请和通讯录上传能力。
|
||||
优化 Facebook、Telegram、WhatsApp 等外部应用入口的显示逻辑。
|
||||
|
||||
# V1.3.4—V1.3.8 2026年3月16日—2026年4月30日 start 多应用模块扩展
|
||||
初始化并持续扩展 Android 封装工程。
|
||||
将命名空间等公共配置统一收敛到项目根目录 build.gradle。
|
||||
新增 REDSPIN8、AA7AU、BNG1AU、FIGHT996、AUPLAYX 等 APP 模块。
|
||||
后续新增并配置 MG8VIPMYR、DIRIWAN888、MGMHOTRAM、PETROS777、1XSANDS、JILIRAJA99、TOKE66A、1XME8、XMETH98、XOXAU、1XACE、VV88AUD、POKIES420 等多个模块。
|
||||
优化 WebView 错误处理、页面日志和空值处理。
|
||||
|
||||
# V1.3.3 2026年3月10日 start 更新AS和 AGP
|
||||
继承 base 有一个app安装权限 纯净版
|
||||
继承 base_noupdata 没有涉及任何系统权限 纯纯纯静版
|
||||
@@ -96,12 +137,3 @@
|
||||
新增通知,跳转查看网页
|
||||
|
||||
新增后台接口配置显示关闭权限,跳转打开facebook,telegram等
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
2
amazy/.gitignore
vendored
Normal file
2
amazy/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/build
|
||||
/release
|
||||
93
amazy/build.gradle
Normal file
93
amazy/build.gradle
Normal file
@@ -0,0 +1,93 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'com.google.gms.google-services'
|
||||
}
|
||||
|
||||
def appOutPutName = "Amazy Taiwan"
|
||||
|
||||
android {
|
||||
namespace rootProject.ext.namespace
|
||||
compileSdk 36
|
||||
defaultConfig {
|
||||
minSdkVersion 24
|
||||
targetSdk 36
|
||||
versionCode rootProject.ext.versionCode
|
||||
versionName rootProject.ext.versionName
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
applicationId "com.company.amazy"
|
||||
|
||||
//app大背景色
|
||||
resValue('color', 'windows_color', '#000000')
|
||||
//底部导航栏颜色 大背景颜色为 windows_color——style_color的上下渐变色
|
||||
resValue('color', 'style_color', '#FFFFFF')
|
||||
//app 名字
|
||||
resValue('string', 'app_name', 'Amazy Taiwan')
|
||||
|
||||
|
||||
buildConfigField "String", "BASE_URL", "\"https://live22x.com/\""
|
||||
buildConfigField "int", "USERID", "311"
|
||||
buildConfigField "boolean", "IS_WHITE", "false"
|
||||
buildConfigField "boolean", "IS_ROUND", "true"
|
||||
buildConfigField "int", "ROUND_RADIUS", "10"
|
||||
buildConfigField "boolean", "HAS_CONTACT", "false"
|
||||
buildConfigField "boolean", "HAS_HOOK", "false"
|
||||
|
||||
}
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
debug {
|
||||
storeFile file('telur33.jks')
|
||||
storePassword "android2014"
|
||||
keyAlias 'key0'
|
||||
keyPassword "android2014"
|
||||
}
|
||||
release {
|
||||
storeFile file('telur33.jks')
|
||||
storePassword "android2014"
|
||||
keyAlias 'key0'
|
||||
keyPassword "android2014"
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility rootProject.ext.JAVA_VERSION
|
||||
targetCompatibility rootProject.ext.JAVA_VERSION
|
||||
}
|
||||
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.all {
|
||||
def outputDir = new File(rootProject.ext.outputPath)
|
||||
outputDir.mkdirs()
|
||||
def outputFileName = "${appOutPutName}.apk"
|
||||
setOutputFileName(outputFileName)
|
||||
def newOutputFile = new File(outputDir, outputFileName)
|
||||
newOutputFile.parentFile.mkdirs()
|
||||
variant.assemble.doLast {
|
||||
try {
|
||||
java.nio.file.Files.copy(
|
||||
outputFile.toPath(),
|
||||
newOutputFile.toPath(),
|
||||
java.nio.file.StandardCopyOption.REPLACE_EXISTING
|
||||
)
|
||||
} catch (java.io.IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(path: ':base')
|
||||
}
|
||||
29
amazy/google-services.json
Normal file
29
amazy/google-services.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"project_info": {
|
||||
"project_number": "905601979176",
|
||||
"project_id": "amazy-e3d7c",
|
||||
"storage_bucket": "amazy-e3d7c.firebasestorage.app"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:905601979176:android:f96e644d9e158dcd48f61d",
|
||||
"android_client_info": {
|
||||
"package_name": "com.company.amazy"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyAsN-ObGVj3vhyNNgiVJKQF_S81puA4ij0"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
||||
BIN
amazy/justlet.jks
Normal file
BIN
amazy/justlet.jks
Normal file
Binary file not shown.
32
amazy/proguard-rules.pro
vendored
Normal file
32
amazy/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
-dontwarn dalvik.**
|
||||
-dontwarn com.tencent.smtt.**
|
||||
|
||||
-keep class com.tencent.smtt.** {
|
||||
*;
|
||||
}
|
||||
|
||||
-keep class com.tencent.tbs.** {
|
||||
*;
|
||||
}
|
||||
67
amazy/src/main/AndroidManifest.xml
Normal file
67
amazy/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- <uses-permission android:name="android.permission.READ_CONTACTS" />-->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
|
||||
<!-- 8.0+系统需要-->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<!--推送权限-->
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<application
|
||||
android:name=".WebApplication"
|
||||
android:allowBackup="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:icon="@mipmap/app_logo"
|
||||
android:label="@string/app_name"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:roundIcon="@mipmap/app_logo"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.AppTheme"
|
||||
android:usesCleartextTraffic="true">
|
||||
|
||||
|
||||
<activity
|
||||
android:name=".IndexActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:exported="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:theme="@style/AppThemeStart">
|
||||
|
||||
<intent-filter>
|
||||
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
|
||||
<service
|
||||
android:name=".MyFirebaseMessageingService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||
android:resource="@mipmap/app_logo" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_color"
|
||||
android:resource="@color/notify_color" />
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_channel_id"
|
||||
android:value="@string/app_name" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
79
amazy/src/main/java/com/webclip/base/IndexActivity.java
Normal file
79
amazy/src/main/java/com/webclip/base/IndexActivity.java
Normal file
@@ -0,0 +1,79 @@
|
||||
package com.webclip.base;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.google.firebase.messaging.FirebaseMessaging;
|
||||
|
||||
public class IndexActivity extends MainActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
initConfig();
|
||||
super.onCreate(savedInstanceState);
|
||||
initWinwdowLogoConfig();
|
||||
// registerFCM();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void regFcm() {
|
||||
super.regFcm();
|
||||
registerFCM();
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册FCM
|
||||
*/
|
||||
private void registerFCM() {
|
||||
//订阅主题
|
||||
LogUtils.i("支持FCM 去注册");
|
||||
try {
|
||||
FirebaseMessaging.getInstance().subscribeToTopic("demo")
|
||||
.addOnCompleteListener(task -> {
|
||||
String msg = "Subscribed";
|
||||
if (!task.isSuccessful()) {
|
||||
msg = "Subscribe failed";
|
||||
}else{
|
||||
checkNotify();
|
||||
}
|
||||
LogUtils.i("支持FCM 结果:"+msg);
|
||||
});
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
LogUtils.i("支持FCM Exception");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于修改大背景渐变色 不设置
|
||||
*/
|
||||
private void initWinwdowLogoConfig() {
|
||||
//全局大背景 一个上下渐变 不要动
|
||||
setBackDrawables(R.drawable.big_bg);
|
||||
setImageView(BuildConfig.IS_ROUND,BuildConfig.ROUND_RADIUS);
|
||||
getWindow().getDecorView().setBackgroundResource(R.drawable.big_bg);
|
||||
|
||||
//需要修改启动页logo在这里弄 一般启动页logo就是app_logo 没特殊要求 不要动
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础配置都在这里
|
||||
* 不要动
|
||||
*/
|
||||
private void initConfig() {
|
||||
|
||||
//===========================以下是APP的配置信息 都写在 app_config.xml中==================================
|
||||
userId = BuildConfig.USERID;
|
||||
saveInt(IndexActivity.this,"user_code",userId);
|
||||
|
||||
saveString(this, "base_url",BuildConfig.BASE_URL);
|
||||
styleColor = getColor(R.color.style_color);
|
||||
windowsColor = getColor(R.color.windows_color);
|
||||
isWhite = BuildConfig.IS_WHITE;
|
||||
hasContact = BuildConfig.HAS_CONTACT;
|
||||
hasHook = BuildConfig.HAS_HOOK;
|
||||
|
||||
//===========================以上是APP的配置信息 都写在 app_config.xml中==================================
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.webclip.base;
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import com.google.firebase.messaging.FirebaseMessagingService;
|
||||
import com.google.firebase.messaging.RemoteMessage;
|
||||
import com.google.gson.Gson;
|
||||
import com.webclip.base.GsonUtils;
|
||||
import com.webclip.base.MessageInfo;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
public class MyFirebaseMessageingService extends FirebaseMessagingService {
|
||||
|
||||
public MyFirebaseMessageingService() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
|
||||
super.onMessageReceived(remoteMessage);
|
||||
Map<String, String> serviceData = remoteMessage.getData(); //后台推送数据
|
||||
if (serviceData != null && serviceData.containsKey("message")) {
|
||||
String value = serviceData.get("message");
|
||||
Gson gson = new Gson();
|
||||
MessageInfo messageInfo = gson.fromJson(value, MessageInfo.class);
|
||||
showNotification(messageInfo);
|
||||
} else {
|
||||
//收到通知 创建notify
|
||||
if (remoteMessage.getNotification() != null) {
|
||||
showNotification(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showNotification(MessageInfo messageInfo) {
|
||||
Intent notifyIntent = new Intent(this, IndexActivity.class);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE) {
|
||||
ComponentName launchComponent = null;
|
||||
launchComponent = getApplication()
|
||||
.getPackageManager()
|
||||
.getLaunchIntentForPackage(getApplication().getPackageName())
|
||||
.getComponent();
|
||||
notifyIntent.setComponent(launchComponent);
|
||||
}
|
||||
notifyIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
notifyIntent.setAction(Intent.ACTION_VIEW);
|
||||
notifyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 必须
|
||||
notifyIntent.putExtra("message", messageInfo);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, new Random().nextInt(10000), notifyIntent, PendingIntent.FLAG_IMMUTABLE);
|
||||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
NotificationChannel channelwinway = null;
|
||||
NotificationCompat.Builder notificationBuilder = null;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
channelwinway = new NotificationChannel(getString(R.string.app_name), "notify", NotificationManager.IMPORTANCE_DEFAULT);
|
||||
channelwinway.enableLights(true);
|
||||
channelwinway.enableVibration(true);
|
||||
notificationManager.createNotificationChannel(channelwinway);
|
||||
notificationBuilder = new NotificationCompat.Builder(this, channelwinway.getId())
|
||||
.setSmallIcon(R.mipmap.app_logo)
|
||||
.setContentTitle(messageInfo.getTitle())
|
||||
.setContentText(messageInfo.getContent())
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntent);
|
||||
} else {
|
||||
notificationBuilder = new NotificationCompat.Builder(this, getString(R.string.app_name))
|
||||
.setSmallIcon(R.mipmap.app_logo)
|
||||
.setContentTitle(messageInfo.getTitle())
|
||||
.setContentText(messageInfo.getContent())
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntent);
|
||||
}
|
||||
notificationManager.notify(0, notificationBuilder.build());
|
||||
}
|
||||
|
||||
private void showNotification(String title, String body) {
|
||||
Intent notifyIntent = new Intent(this, IndexActivity.class);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE) {
|
||||
ComponentName launchComponent = null;
|
||||
launchComponent = getApplication()
|
||||
.getPackageManager()
|
||||
.getLaunchIntentForPackage(getApplication().getPackageName())
|
||||
.getComponent();
|
||||
notifyIntent.setComponent(launchComponent);
|
||||
}
|
||||
notifyIntent.putExtra("message", body);
|
||||
notifyIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
notifyIntent.setAction(Intent.ACTION_VIEW);
|
||||
notifyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 必须
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, new Random().nextInt(10000), notifyIntent, PendingIntent.FLAG_IMMUTABLE);
|
||||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
NotificationChannel channelwinway = null;
|
||||
NotificationCompat.Builder notificationBuilder = null;
|
||||
MessageInfo messageInfo = GsonUtils.getObjFromJSON(body, MessageInfo.class);
|
||||
if (messageInfo != null) {
|
||||
body = messageInfo.getContent();
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
channelwinway = new NotificationChannel(getString(R.string.app_name), "notify", NotificationManager.IMPORTANCE_DEFAULT);
|
||||
channelwinway.enableLights(true);
|
||||
channelwinway.enableVibration(true);
|
||||
notificationManager.createNotificationChannel(channelwinway);
|
||||
notificationBuilder = new NotificationCompat.Builder(this, channelwinway.getId())
|
||||
.setSmallIcon(R.mipmap.app_logo)
|
||||
.setContentTitle(title)
|
||||
.setContentText(body)
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntent);
|
||||
} else {
|
||||
notificationBuilder = new NotificationCompat.Builder(this, getString(R.string.app_name))
|
||||
.setSmallIcon(R.mipmap.app_logo)
|
||||
.setContentTitle(title)
|
||||
.setContentText(body)
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntent);
|
||||
}
|
||||
notificationManager.notify(0, notificationBuilder.build());
|
||||
}
|
||||
}
|
||||
19
amazy/src/main/java/com/webclip/base/WebApplication.java
Normal file
19
amazy/src/main/java/com/webclip/base/WebApplication.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package com.webclip.base;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import com.webclip.base.LogUtils;
|
||||
|
||||
public class WebApplication extends Application {
|
||||
|
||||
|
||||
public static Context application;
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
// 设置开启优化方案
|
||||
application = this;
|
||||
LogUtils.isDebug = BuildConfig.BUILD_TYPE.equals("debug");
|
||||
}
|
||||
}
|
||||
9
amazy/src/main/res/drawable/big_bg.xml
Normal file
9
amazy/src/main/res/drawable/big_bg.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:angle="270"
|
||||
android:startColor="@color/windows_color"
|
||||
android:centerColor="@color/windows_color"
|
||||
android:endColor="@color/style_color"/>
|
||||
</shape>
|
||||
BIN
amazy/src/main/res/mipmap-xxhdpi/app_logo.jpg
Normal file
BIN
amazy/src/main/res/mipmap-xxhdpi/app_logo.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
91
amazy/src/main/res/values/themes.xml
Normal file
91
amazy/src/main/res/values/themes.xml
Normal file
@@ -0,0 +1,91 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar.Bridge">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/purple_500</item>
|
||||
<item name="colorPrimaryVariant">@color/purple_700</item>
|
||||
<item name="colorOnPrimary">@color/white</item>
|
||||
<!-- Secondary brand color. -->
|
||||
<item name="colorSecondary">@color/teal_200</item>
|
||||
<item name="colorSecondaryVariant">@color/teal_700</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="android:windowBackground">#000000</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Theme.Calculcator1" parent="Theme.MaterialComponents.DayNight.DarkActionBar.Bridge">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/purple_500</item>
|
||||
<item name="colorPrimaryVariant">@color/purple_700</item>
|
||||
<item name="colorOnPrimary">@color/white</item>
|
||||
<!-- Secondary brand color. -->
|
||||
<item name="colorSecondary">@color/teal_200</item>
|
||||
<item name="colorSecondaryVariant">@color/teal_700</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<item name="android:windowFullscreen">true</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
|
||||
|
||||
<declare-styleable name="CircleImageView">
|
||||
<attr name="ease_border_color" format="color" />
|
||||
<attr name="ease_border_width" format="dimension" />
|
||||
<attr name="ease_press_alpha" format="integer" />
|
||||
<attr name="ease_press_color" format="color" />
|
||||
<attr name="ease_radius" format="dimension" />
|
||||
<attr name="es_shape_type" format="enum">
|
||||
<enum name="none" value="0" />
|
||||
<enum name="round" value="1" />
|
||||
<enum name="rectangle" value="2" />
|
||||
</attr>
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<!-- 注意:当前AppTheme主题,在values-v23中单独重复维护。原因是Android 6以下系统不支持设置
|
||||
系统状态栏颜色,如果按照设计,状态栏使用素色则在android6以下手机上就看不清系统状态栏文字了(
|
||||
因为系统文字是白色)。在values-v23表示当Android 23(即android 6)及以上版本将自动使用该目录
|
||||
下的主题(即 colorPrimaryDark 使用素色,从而跟标题栏颜色保持一致,实现沉浸式ui效果)。-->
|
||||
<style name="AppThemeStart" parent="@style/Theme.AppCompat.Light.NoActionBar">
|
||||
<item name="android:windowTranslucentStatus">false</item>
|
||||
<item name="android:windowTranslucentNavigation">false</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="colorPrimary">@color/windows_color</item>
|
||||
<item name="colorPrimaryDark">@color/windows_color</item>
|
||||
<item name="colorAccent">@color/windows_color</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<!-- 隐藏Activity窗口的Title标题栏 -->
|
||||
<item name="windowNoTitle">true</item>
|
||||
<!-- <item name="android:windowFullscreen">true</item>-->
|
||||
<!-- <item name="android:windowBackground">@drawable/splah_bg</item>-->
|
||||
|
||||
<item name="android:navigationBarColor">@color/style_color</item>
|
||||
<!-- <item name="android:windowBackground">@mipmap/big_bg</item>-->
|
||||
<item name="android:forceDarkAllowed" tools:ignore="NewApi">false</item>
|
||||
<item name="android:windowBackground">@drawable/big_bg</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="MaterialDesignDialog" parent="@style/Theme.AppCompat.Dialog">
|
||||
<!-- 背景透明 -->
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<!-- 浮于Activity之上 -->
|
||||
<item name="android:windowIsFloating">true</item>
|
||||
<!-- 边框 -->
|
||||
<item name="android:windowFrame">@null</item>
|
||||
<!-- Dialog以外的区域模糊效果 -->
|
||||
<item name="android:backgroundDimEnabled">true</item>
|
||||
<!-- 无标题 -->
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<!-- 半透明 -->
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:windowCloseOnTouchOutside">true</item>
|
||||
</style>
|
||||
</resources>
|
||||
10
amazy/src/main/res/xml/app_updater_paths.xml
Normal file
10
amazy/src/main/res/xml/app_updater_paths.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths>
|
||||
<root-path name="app_root_path" path="/"/>
|
||||
<external-path name="app_external_path" path="/"/>
|
||||
<external-cache-path name="app_external_cache_path" path="/"/>
|
||||
<external-files-path name="app_external_files_path" path="/"/>
|
||||
<files-path name="app_files_path" path="/"/>
|
||||
<cache-path name="app_cache_path" path="/"/>
|
||||
|
||||
</paths>
|
||||
4
amazy/src/main/res/xml/network_security_config.xml
Normal file
4
amazy/src/main/res/xml/network_security_config.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<base-config cleartextTrafficPermitted="true" />
|
||||
</network-security-config>
|
||||
13
amazy/src/main/res/xml/provider_paths.xml
Normal file
13
amazy/src/main/res/xml/provider_paths.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding= "utf-8"?>
|
||||
<resources>
|
||||
<paths >
|
||||
<external-path name="external_files" path="."/>
|
||||
<root-path name="root" path="." />
|
||||
<files-path name="files" path="." />
|
||||
<cache-path name="cache" path="." />
|
||||
<external-files-path name="external_files_f" path="." />
|
||||
<external-cache-path name="external_cache" path="." />
|
||||
</paths >
|
||||
</resources>
|
||||
<!-- 适配7.0及其以上,配合com.eva.android.OpenFileUtil,用于解决调用系统Intent查看大文件内
|
||||
容、拍照保存图片的功能时出现"android.os.FileUriExposedException"异常的问题 -->
|
||||
BIN
amazy/telur33.jks
Normal file
BIN
amazy/telur33.jks
Normal file
Binary file not shown.
@@ -38,12 +38,6 @@ public interface ApiService {
|
||||
@PUT("api/statistics/use")
|
||||
Observable<Result> totalTongJi(@Body Map<String, Object> map);
|
||||
|
||||
/**
|
||||
* 统计通知
|
||||
*/
|
||||
@POST("api/push/statistics")
|
||||
Observable<Result> totalNotify(@Body Map<String, Object> map);
|
||||
|
||||
/**
|
||||
* 上传通讯录
|
||||
*/
|
||||
@@ -60,7 +54,27 @@ public interface ApiService {
|
||||
* @return
|
||||
*/
|
||||
@GET("api/push/pushRecords")
|
||||
Observable<Result<ResultDataInfo<MessageInfo>>> getNotifyList(@Query("userId") int userid, @Query("page") int page, @Query("size") int size);
|
||||
Observable<Result<ResultDataInfo<MessageInfo>>> getNotifyList(
|
||||
@Query("userId") int userid,
|
||||
@Query("page") int page,
|
||||
@Query("size") int size,
|
||||
@Query("isScheduler") int isScheduler
|
||||
);
|
||||
|
||||
/**
|
||||
* 获取通知详情。查询成功后,后端会异步将该通知的阅读次数加一。
|
||||
*/
|
||||
@GET("api/push/client/pushRecord/{id}")
|
||||
Observable<Result<MessageInfo>> getNotifyDetail(@Path("id") int pushId);
|
||||
|
||||
|
||||
/**
|
||||
* 首次采集上报站点用户信息(从网页 localStorage 抓取并净化后的登录用户)
|
||||
* body: userId(应用在系统中的用户ID)、domain(站点域名)、deviceType(IOS/ANDROID)、data(用户对象JSON,必须为对象)
|
||||
* data.mobile 必填,后端以 mobile 为全局唯一键,重复提交不覆盖
|
||||
*/
|
||||
@POST("api/client/user-info")
|
||||
Observable<Result> saveCollectedUserInfo(@Body Map<String, Object> map);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -62,7 +62,9 @@ import java.io.InputStreamReader;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
@@ -572,7 +574,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
public void getNotifyList() {
|
||||
|
||||
Api.getInstance().getNotifyList(userId, 1, 1)
|
||||
Api.getInstance().getNotifyList(userId, 1, 1, 0)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BaseObserver<>() {
|
||||
@@ -956,14 +958,15 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
public void recordNotify(int pushId) {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("pushId", pushId);
|
||||
Api.getInstance().totalNotify(map)
|
||||
if (pushId <= 0) {
|
||||
return;
|
||||
}
|
||||
Api.getInstance().getNotifyDetail(pushId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BaseObserver<>() {
|
||||
.subscribe(new BaseObserver<Result<MessageInfo>>() {
|
||||
@Override
|
||||
public void onSuccess(Result o) {
|
||||
public void onSuccess(Result<MessageInfo> o) {
|
||||
|
||||
}
|
||||
|
||||
@@ -972,7 +975,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError2(Result o) {
|
||||
public void onError2(Result<MessageInfo> o) {
|
||||
|
||||
}
|
||||
});
|
||||
@@ -983,6 +986,52 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
boolean hasSignIn = false;
|
||||
|
||||
/**
|
||||
* 需要在网页 localStorage 中探测的用户信息字段(按优先级遍历全部候选 key)
|
||||
*/
|
||||
private static final String[] SITE_USER_STORAGE_KEYS = {
|
||||
"USER", "user", "userInfo", "user_info", "userinfo", "userData", "user_data",
|
||||
"userDetail", "userDetails", "currentUser", "current_user", "currentUserInfo",
|
||||
"member", "memberInfo", "member_info", "memberData", "member_data",
|
||||
"loginUser", "login_user", "loginInfo", "login_info", "loginData",
|
||||
"authUser", "auth_user", "auth", "authInfo", "auth_info", "authData",
|
||||
"account", "accountInfo", "account_info", "accountData",
|
||||
"player", "playerInfo", "player_info", "playerData", "player_data",
|
||||
"profile", "userProfile", "user_profile", "customer", "customerInfo",
|
||||
"me", "sessionUser", "session_user"
|
||||
};
|
||||
|
||||
// 抓到用户信息之前的轮询间隔:30 秒
|
||||
private static final long SITE_USER_POLL_INTERVAL_SHORT = 30 * 1000L;
|
||||
// 抓到用户信息之后的复查间隔:1 天
|
||||
private static final long SITE_USER_POLL_INTERVAL_LONG = 24 * 60 * 60 * 1000L;
|
||||
|
||||
/**
|
||||
* 手机号候选字段(用于前端去重;原始数据没有 mobile 字段时,取这里命中的值补进 data.mobile)
|
||||
*/
|
||||
private static final String[] SITE_USER_PHONE_KEYS = {
|
||||
"mobile", "mobileNo", "mobileNum", "mobileNumber", "mobile_number", "mobile_no",
|
||||
"phone", "phoneNo", "phoneNum", "phoneNumber", "phone_number", "phone_no",
|
||||
"tel", "telephone", "cellphone", "cell", "contact", "contactNo", "contactNumber",
|
||||
"msisdn"
|
||||
};
|
||||
// 本地保存的已上报手机号集合,用于判断多个缓存用户是否已经上报过
|
||||
private static final String SP_KEY_SITE_USER_DEDUP = "site_user_dedup";
|
||||
// 上报设备类型(后端接口要求 IOS 或 ANDROID)
|
||||
private static final String SITE_USER_DEVICE_TYPE = "ANDROID";
|
||||
|
||||
private boolean siteUserPollingStarted = false;
|
||||
private long siteUserPollInterval = SITE_USER_POLL_INTERVAL_SHORT;
|
||||
|
||||
private final Runnable siteUserPollRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
pollSiteUserOnce();
|
||||
// 探测一次后按当前间隔继续排下一次
|
||||
handler.postDelayed(this, siteUserPollInterval);
|
||||
}
|
||||
};
|
||||
|
||||
private boolean isMainPageUrl(String targetUrl) {
|
||||
return !TextUtils.isEmpty(targetUrl) && !TextUtils.isEmpty(url) && targetUrl.startsWith(url);
|
||||
}
|
||||
@@ -997,6 +1046,244 @@ public class MainActivity extends AppCompatActivity {
|
||||
LogUtils.i("WebViewURL[" + stage + "]: " + rawUrl + " | host=" + host + " | scheme=" + uri.getScheme());
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动 localStorage 用户信息轮询(全局只启动一次)。
|
||||
* 若本地已有去重记录说明之前已命中,直接按长间隔复查是否变化。
|
||||
*/
|
||||
private void startSiteUserPolling() {
|
||||
if (siteUserPollingStarted) {
|
||||
return;
|
||||
}
|
||||
siteUserPollingStarted = true;
|
||||
siteUserPollInterval = getReportedSiteUserKeys().isEmpty()
|
||||
? SITE_USER_POLL_INTERVAL_SHORT : SITE_USER_POLL_INTERVAL_LONG;
|
||||
handler.postDelayed(siteUserPollRunnable, siteUserPollInterval);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取本地已上报手机号集合。
|
||||
* 兼容旧版本保存的单个字符串格式,升级后会逐步转换为 JSON 数组格式。
|
||||
*/
|
||||
private HashSet<String> getReportedSiteUserKeys() {
|
||||
HashSet<String> keys = new HashSet<>();
|
||||
String stored = getString(MainActivity.this, SP_KEY_SITE_USER_DEDUP, "");
|
||||
if (TextUtils.isEmpty(stored)) {
|
||||
return keys;
|
||||
}
|
||||
try {
|
||||
List<String> storedKeys = new Gson().fromJson(stored,
|
||||
new com.google.gson.reflect.TypeToken<List<String>>() {
|
||||
}.getType());
|
||||
if (storedKeys != null) {
|
||||
keys.addAll(storedKeys);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 兼容旧版本保存的手机号或整份用户 JSON
|
||||
}
|
||||
if (keys.isEmpty() && !stored.trim().startsWith("[")) {
|
||||
keys.add(stored);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
private void saveReportedSiteUserKeys(Set<String> keys) {
|
||||
saveString(MainActivity.this, SP_KEY_SITE_USER_DEDUP, new Gson().toJson(keys));
|
||||
}
|
||||
|
||||
private void removeReportedSiteUserKey(String key) {
|
||||
HashSet<String> keys = getReportedSiteUserKeys();
|
||||
if (keys.remove(key)) {
|
||||
saveReportedSiteUserKeys(keys);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行一次 localStorage 探测:遍历所有候选 key,读取并净化全部有效用户对象。
|
||||
*/
|
||||
private void pollSiteUserOnce() {
|
||||
if (activityMain2Binding == null || activityMain2Binding.webview == null) {
|
||||
return;
|
||||
}
|
||||
String keysJson = new Gson().toJson(SITE_USER_STORAGE_KEYS);
|
||||
String js = "(function(){try{"
|
||||
+ "var KS=" + keysJson + ";"
|
||||
+ "function readAllRaw(){var out=[];for(var i=0;i<KS.length;i++){var r=localStorage.getItem(KS[i]);"
|
||||
+ "if(r!=null&&String(r).trim())out.push(r);}return out;}"
|
||||
+ "function sani(raw){if(raw==null)return null;var t=String(raw).trim();if(!t)return null;"
|
||||
+ "var d;try{d=JSON.parse(t);}catch(e){return null;}"
|
||||
+ "if(d===null||typeof d!=='object'||Array.isArray(d))return null;"
|
||||
+ "['bonus','gameAccess','time','timebonus','rollover','banks'].forEach(function(k){if(k in d)delete d[k];});"
|
||||
+ "if(Object.keys(d).length===0)return null;return JSON.stringify(d);}"
|
||||
+ "var out=[];var raws=readAllRaw();"
|
||||
+ "for(var j=0;j<raws.length;j++){var s=sani(raws[j]);if(s){out.push(JSON.parse(s));}}"
|
||||
+ "return JSON.stringify(out);"
|
||||
+ "}catch(e){return null;}})();";
|
||||
try {
|
||||
activityMain2Binding.webview.evaluateJavascript(js, this::onSiteUserResult);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 JS 探测结果。evaluateJavascript 回调返回的是 JS 值的 JSON 编码形式,字符串需要先解一层。
|
||||
*/
|
||||
private void onSiteUserResult(String rawResult) {
|
||||
if (TextUtils.isEmpty(rawResult) || "null".equals(rawResult)) {
|
||||
// 无有效用户信息,保持短间隔继续探测
|
||||
return;
|
||||
}
|
||||
String usersJson;
|
||||
try {
|
||||
usersJson = new Gson().fromJson(rawResult, String.class);
|
||||
} catch (Exception e) {
|
||||
usersJson = rawResult;
|
||||
}
|
||||
if (TextUtils.isEmpty(usersJson) || "[]".equals(usersJson)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<HashMap<String, Object>> userInfos;
|
||||
try {
|
||||
userInfos = new Gson().fromJson(usersJson,
|
||||
new com.google.gson.reflect.TypeToken<List<HashMap<String, Object>>>() {
|
||||
}.getType());
|
||||
} catch (Exception e) {
|
||||
return;
|
||||
}
|
||||
if (userInfos == null || userInfos.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
HashSet<String> reportedKeys = getReportedSiteUserKeys();
|
||||
boolean hasUserWithPhone = false;
|
||||
for (HashMap<String, Object> userInfoMap : userInfos) {
|
||||
if (userInfoMap == null || userInfoMap.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
String userInfo = new Gson().toJson(userInfoMap);
|
||||
String phone = extractPhone(userInfo);
|
||||
if (TextUtils.isEmpty(phone)) {
|
||||
continue;
|
||||
}
|
||||
hasUserWithPhone = true;
|
||||
if (reportedKeys.contains(phone)) {
|
||||
continue;
|
||||
}
|
||||
// 先加入集合,避免多个候选 key 或下一轮轮询重复发起请求。
|
||||
reportedKeys.add(phone);
|
||||
reportSiteUser(userInfo, phone);
|
||||
}
|
||||
|
||||
if (hasUserWithPhone) {
|
||||
siteUserPollInterval = SITE_USER_POLL_INTERVAL_LONG;
|
||||
saveReportedSiteUserKeys(reportedKeys);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从用户信息 JSON 中提取手机号(手机号字段名不一定是 mobile)。
|
||||
*/
|
||||
private String extractPhone(String userInfoJson) {
|
||||
try {
|
||||
HashMap<String, Object> map = new Gson().fromJson(userInfoJson,
|
||||
new com.google.gson.reflect.TypeToken<HashMap<String, Object>>() {
|
||||
}.getType());
|
||||
if (map != null) {
|
||||
for (String key : SITE_USER_PHONE_KEYS) {
|
||||
Object v = map.get(key);
|
||||
if (v != null) {
|
||||
String s = String.valueOf(v).trim();
|
||||
if (!s.isEmpty() && !"null".equals(s)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 解析失败时无手机号,返回空
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前 WebView 所在站点的域名(host)。
|
||||
*/
|
||||
private String getCurrentDomain() {
|
||||
try {
|
||||
String u = activityMain2Binding.webview.getUrl();
|
||||
if (!TextUtils.isEmpty(u)) {
|
||||
String host = Uri.parse(u).getHost();
|
||||
if (host != null) {
|
||||
return host;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 上报站点用户信息,绑定对应 app 的网站ID(userId)、站点域名(domain)和设备类型(deviceType)。
|
||||
* 按后端接口文档:data 必须是 JSON 对象,data.mobile 为全局唯一键;
|
||||
* 原始数据没有 mobile 字段时,用电话候选字段的值补进 data.mobile。
|
||||
*/
|
||||
private void reportSiteUser(String userInfo, final String dedupKey) {
|
||||
HashMap<String, Object> data;
|
||||
try {
|
||||
data = new Gson().fromJson(userInfo,
|
||||
new com.google.gson.reflect.TypeToken<HashMap<String, Object>>() {
|
||||
}.getType());
|
||||
} catch (Exception e) {
|
||||
return;
|
||||
}
|
||||
if (data == null || data.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// data.mobile 兜底:没有 mobile 时用电话候选字段补一个
|
||||
Object mobileVal = data.get("mobile");
|
||||
boolean hasMobile = mobileVal != null
|
||||
&& String.valueOf(mobileVal).trim().length() > 0
|
||||
&& !"null".equals(String.valueOf(mobileVal).trim());
|
||||
if (!hasMobile) {
|
||||
String phone = extractPhone(userInfo);
|
||||
if (TextUtils.isEmpty(phone)) {
|
||||
// 完全没有电话字段:后端要求 data.mobile 必填,本次跳过,保持轮询等待
|
||||
LogUtils.i("站点用户无手机号字段,跳过上报");
|
||||
return;
|
||||
}
|
||||
data.put("mobile", phone);
|
||||
}
|
||||
|
||||
HashMap<String, Object> body = new HashMap<>();
|
||||
body.put("userId", userId);
|
||||
body.put("domain", getCurrentDomain());
|
||||
body.put("deviceType", SITE_USER_DEVICE_TYPE);
|
||||
body.put("data", data);
|
||||
Api.getInstance().saveCollectedUserInfo(body)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BaseObserver<Result>() {
|
||||
@Override
|
||||
public void onSuccess(Result o) {
|
||||
LogUtils.i("站点用户信息上报成功");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int code, String msg) {
|
||||
// 仅清掉当前用户的去重记录,下次轮询可重试其他已成功用户
|
||||
removeReportedSiteUserKey(dedupKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError2(Result o) {
|
||||
removeReportedSiteUserKey(dedupKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// WebView webViews;
|
||||
WebViewClient webViewClient = new WebViewClient() {
|
||||
@@ -1017,6 +1304,9 @@ public class MainActivity extends AppCompatActivity {
|
||||
hasSignIn = true;
|
||||
}
|
||||
|
||||
// 页面首次加载完成后启动 localStorage 用户信息轮询
|
||||
startSiteUserPolling();
|
||||
|
||||
int w = View.MeasureSpec.makeMeasureSpec(0,
|
||||
View.MeasureSpec.UNSPECIFIED);
|
||||
int h = View.MeasureSpec.makeMeasureSpec(0,
|
||||
@@ -1350,6 +1640,8 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
// 停止用户信息轮询
|
||||
handler.removeCallbacks(siteUserPollRunnable);
|
||||
if (activityMain2Binding.webview!= null) {
|
||||
//加载null内容
|
||||
activityMain2Binding.webview.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
|
||||
|
||||
@@ -10,6 +10,8 @@ public class MessageInfo implements Serializable {
|
||||
private int pushId;
|
||||
private String createTime;
|
||||
private int recordId;
|
||||
private long receiveTimes;
|
||||
private long readTimes;
|
||||
public int status;
|
||||
private String jumpUrl;
|
||||
private boolean isShowAll = false;
|
||||
@@ -30,6 +32,22 @@ public class MessageInfo implements Serializable {
|
||||
this.recordId = recordId;
|
||||
}
|
||||
|
||||
public long getReceiveTimes() {
|
||||
return receiveTimes;
|
||||
}
|
||||
|
||||
public void setReceiveTimes(long receiveTimes) {
|
||||
this.receiveTimes = receiveTimes;
|
||||
}
|
||||
|
||||
public long getReadTimes() {
|
||||
return readTimes;
|
||||
}
|
||||
|
||||
public void setReadTimes(long readTimes) {
|
||||
this.readTimes = readTimes;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ public class MyNotifyListAdapter extends RecyclerView.Adapter<MyNotifyListAdapte
|
||||
|
||||
private List<MessageInfo> listdata;
|
||||
private onItemClickPostionListener itemClickPostionListener;
|
||||
private onItemExpandListener itemExpandListener;
|
||||
private Context context;
|
||||
private MessageInfo messageItem;
|
||||
|
||||
@@ -49,6 +50,10 @@ public class MyNotifyListAdapter extends RecyclerView.Adapter<MyNotifyListAdapte
|
||||
this.itemClickPostionListener = onItemClick;
|
||||
}
|
||||
|
||||
public void setOnItemExpand(onItemExpandListener onItemExpand) {
|
||||
this.itemExpandListener = onItemExpand;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
@@ -103,7 +108,8 @@ public class MyNotifyListAdapter extends RecyclerView.Adapter<MyNotifyListAdapte
|
||||
holder.itemNotifyListBinding.tvMsgTime.setText(messageInfo.getCreateTime());
|
||||
holder.itemNotifyListBinding.ivNotifyjumpclick.setVisibility(View.GONE);
|
||||
|
||||
holder.itemNotifyListBinding.lookIv.setText(longTime(messageInfo.getCreateTime()));
|
||||
// 左下角眼睛图标显示后端返回的真实阅读次数
|
||||
holder.itemNotifyListBinding.lookIv.setText(String.valueOf(messageInfo.getReadTimes()));
|
||||
if (!TextUtils.isEmpty(messageInfo.getImage())) {
|
||||
LogUtils.i("地址是啥:"+messageInfo.getImage());
|
||||
holder.itemNotifyListBinding.ivNotifyimage.setVisibility(View.VISIBLE);
|
||||
@@ -126,7 +132,11 @@ public class MyNotifyListAdapter extends RecyclerView.Adapter<MyNotifyListAdapte
|
||||
holder.itemNotifyListBinding.layoutMore.setVisibility(View.GONE);
|
||||
}
|
||||
holder.itemView.setOnClickListener(view -> {
|
||||
messageInfo.setShowAll(!messageInfo.isShowAll());
|
||||
boolean willExpand = !messageInfo.isShowAll();
|
||||
messageInfo.setShowAll(willExpand);
|
||||
if (willExpand && itemExpandListener != null) {
|
||||
itemExpandListener.item(messageInfo);
|
||||
}
|
||||
notifyItemChanged(position);
|
||||
});
|
||||
|
||||
@@ -167,4 +177,8 @@ public class MyNotifyListAdapter extends RecyclerView.Adapter<MyNotifyListAdapte
|
||||
void item(int position);
|
||||
}
|
||||
|
||||
public interface onItemExpandListener {
|
||||
void item(MessageInfo messageInfo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ public class NotifyListActivity extends AppCompatActivity {
|
||||
adapter.setOnItemClick(position -> {
|
||||
try{
|
||||
MessageInfo messageInfo = listdata.get(position);
|
||||
recordNotify(messageInfo);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(messageInfo.getJumpUrl()));
|
||||
startActivity(intent);
|
||||
}catch (Exception e){
|
||||
@@ -89,8 +90,44 @@ public class NotifyListActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
});
|
||||
adapter.setOnItemExpand(this::recordNotify);
|
||||
getNotifyList();
|
||||
}
|
||||
|
||||
/** 小铃铛列表中用户展开通知时,按文档查询详情并异步增加阅读次数。 */
|
||||
private void recordNotify(MessageInfo messageInfo) {
|
||||
if (messageInfo == null) {
|
||||
return;
|
||||
}
|
||||
int pushId = messageInfo.getPushId() > 0 ? messageInfo.getPushId() : messageInfo.getRecordId();
|
||||
if (pushId <= 0) {
|
||||
return;
|
||||
}
|
||||
Api.getInstance().getNotifyDetail(pushId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BaseObserver<Result<MessageInfo>>() {
|
||||
@Override
|
||||
public void onSuccess(Result<MessageInfo> o) {
|
||||
// 后端采用异步最终一致,详情响应可能仍是加一前的值;稍后刷新列表读取最终值。
|
||||
if (o != null && o.data != null && o.data.getReadTimes() > messageInfo.getReadTimes()) {
|
||||
messageInfo.setReadTimes(o.data.getReadTimes());
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
activityNotifylistBinding.recyclerNofity.postDelayed(() -> getNotifyList(), 1200L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int code, String msg) {
|
||||
LogUtils.i("阅读次数上报失败 pushId=" + pushId + ", error=" + msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError2(Result<MessageInfo> o) {
|
||||
LogUtils.i("阅读次数上报失败 pushId=" + pushId);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 启用Edge-to-Edge模式(核心方法)
|
||||
*
|
||||
@@ -121,7 +158,7 @@ public class NotifyListActivity extends AppCompatActivity {
|
||||
|
||||
public void getNotifyList() {
|
||||
//通知列表
|
||||
Api.getInstance().getNotifyList(userId, page, 10)
|
||||
Api.getInstance().getNotifyList(userId, page, 10, 0)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BaseObserver<>() {
|
||||
|
||||
@@ -38,13 +38,6 @@ public interface ApiService {
|
||||
@PUT("api/statistics/use")
|
||||
Observable<Result> totalTongJi(@Body Map<String, Object> map);
|
||||
|
||||
/**
|
||||
* 统计通知
|
||||
*/
|
||||
@POST("api/push/statistics")
|
||||
Observable<Result> totalNotify(@Body Map<String, Object> map);
|
||||
|
||||
|
||||
/**
|
||||
* 获取通知列表
|
||||
* @param userid
|
||||
@@ -53,7 +46,18 @@ public interface ApiService {
|
||||
* @return
|
||||
*/
|
||||
@GET("api/push/pushRecords")
|
||||
Observable<Result<ResultDataInfo<MessageInfo>>> getNotifyList(@Query("userId") int userid, @Query("page") int page, @Query("size") int size);
|
||||
Observable<Result<ResultDataInfo<MessageInfo>>> getNotifyList(
|
||||
@Query("userId") int userid,
|
||||
@Query("page") int page,
|
||||
@Query("size") int size,
|
||||
@Query("isScheduler") int isScheduler
|
||||
);
|
||||
|
||||
/**
|
||||
* 获取通知详情。查询成功后,后端会异步将该通知的阅读次数加一。
|
||||
*/
|
||||
@GET("api/push/client/pushRecord/{id}")
|
||||
Observable<Result<MessageInfo>> getNotifyDetail(@Path("id") int pushId);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -547,7 +547,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
|
||||
public void getNotifyList() {
|
||||
|
||||
Api.getInstance().getNotifyList(userId, 1, 1)
|
||||
Api.getInstance().getNotifyList(userId, 1, 1, 0)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BaseObserver<>() {
|
||||
@@ -814,14 +814,15 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
public void recordNotify(int pushId) {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("pushId", pushId);
|
||||
Api.getInstance().totalNotify(map)
|
||||
if (pushId <= 0) {
|
||||
return;
|
||||
}
|
||||
Api.getInstance().getNotifyDetail(pushId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BaseObserver<>() {
|
||||
.subscribe(new BaseObserver<Result<MessageInfo>>() {
|
||||
@Override
|
||||
public void onSuccess(Result o) {
|
||||
public void onSuccess(Result<MessageInfo> o) {
|
||||
|
||||
}
|
||||
|
||||
@@ -830,7 +831,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError2(Result o) {
|
||||
public void onError2(Result<MessageInfo> o) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -10,6 +10,8 @@ public class MessageInfo implements Serializable {
|
||||
private int pushId;
|
||||
private String createTime;
|
||||
private int recordId;
|
||||
private long receiveTimes;
|
||||
private long readTimes;
|
||||
public int status;
|
||||
private String jumpUrl;
|
||||
private boolean isShowAll = false;
|
||||
@@ -30,6 +32,22 @@ public class MessageInfo implements Serializable {
|
||||
this.recordId = recordId;
|
||||
}
|
||||
|
||||
public long getReceiveTimes() {
|
||||
return receiveTimes;
|
||||
}
|
||||
|
||||
public void setReceiveTimes(long receiveTimes) {
|
||||
this.receiveTimes = receiveTimes;
|
||||
}
|
||||
|
||||
public long getReadTimes() {
|
||||
return readTimes;
|
||||
}
|
||||
|
||||
public void setReadTimes(long readTimes) {
|
||||
this.readTimes = readTimes;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ public class MyNotifyListAdapter extends RecyclerView.Adapter<MyNotifyListAdapte
|
||||
|
||||
private List<MessageInfo> listdata;
|
||||
private onItemClickPostionListener itemClickPostionListener;
|
||||
private onItemExpandListener itemExpandListener;
|
||||
private Context context;
|
||||
private MessageInfo messageItem;
|
||||
|
||||
@@ -49,6 +50,10 @@ public class MyNotifyListAdapter extends RecyclerView.Adapter<MyNotifyListAdapte
|
||||
this.itemClickPostionListener = onItemClick;
|
||||
}
|
||||
|
||||
public void setOnItemExpand(onItemExpandListener onItemExpand) {
|
||||
this.itemExpandListener = onItemExpand;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
@@ -103,7 +108,8 @@ public class MyNotifyListAdapter extends RecyclerView.Adapter<MyNotifyListAdapte
|
||||
holder.itemNotifyListBinding.tvMsgTime.setText(messageInfo.getCreateTime());
|
||||
holder.itemNotifyListBinding.ivNotifyjumpclick.setVisibility(View.GONE);
|
||||
|
||||
holder.itemNotifyListBinding.lookIv.setText(longTime(messageInfo.getCreateTime()));
|
||||
// 左下角眼睛图标显示后端返回的真实阅读次数
|
||||
holder.itemNotifyListBinding.lookIv.setText(String.valueOf(messageInfo.getReadTimes()));
|
||||
if (!TextUtils.isEmpty(messageInfo.getImage())) {
|
||||
LogUtils.i("地址是啥:"+messageInfo.getImage());
|
||||
holder.itemNotifyListBinding.ivNotifyimage.setVisibility(View.VISIBLE);
|
||||
@@ -126,7 +132,11 @@ public class MyNotifyListAdapter extends RecyclerView.Adapter<MyNotifyListAdapte
|
||||
holder.itemNotifyListBinding.layoutMore.setVisibility(View.GONE);
|
||||
}
|
||||
holder.itemView.setOnClickListener(view -> {
|
||||
messageInfo.setShowAll(!messageInfo.isShowAll());
|
||||
boolean willExpand = !messageInfo.isShowAll();
|
||||
messageInfo.setShowAll(willExpand);
|
||||
if (willExpand && itemExpandListener != null) {
|
||||
itemExpandListener.item(messageInfo);
|
||||
}
|
||||
notifyItemChanged(position);
|
||||
});
|
||||
|
||||
@@ -167,4 +177,8 @@ public class MyNotifyListAdapter extends RecyclerView.Adapter<MyNotifyListAdapte
|
||||
void item(int position);
|
||||
}
|
||||
|
||||
public interface onItemExpandListener {
|
||||
void item(MessageInfo messageInfo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ public class NotifyListActivity extends AppCompatActivity {
|
||||
adapter.setOnItemClick(position -> {
|
||||
try{
|
||||
MessageInfo messageInfo = listdata.get(position);
|
||||
recordNotify(messageInfo);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(messageInfo.getJumpUrl()));
|
||||
startActivity(intent);
|
||||
}catch (Exception e){
|
||||
@@ -89,8 +90,44 @@ public class NotifyListActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
});
|
||||
adapter.setOnItemExpand(this::recordNotify);
|
||||
getNotifyList();
|
||||
}
|
||||
|
||||
/** 小铃铛列表中用户展开通知时,按文档查询详情并异步增加阅读次数。 */
|
||||
private void recordNotify(MessageInfo messageInfo) {
|
||||
if (messageInfo == null) {
|
||||
return;
|
||||
}
|
||||
int pushId = messageInfo.getPushId() > 0 ? messageInfo.getPushId() : messageInfo.getRecordId();
|
||||
if (pushId <= 0) {
|
||||
return;
|
||||
}
|
||||
Api.getInstance().getNotifyDetail(pushId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BaseObserver<Result<MessageInfo>>() {
|
||||
@Override
|
||||
public void onSuccess(Result<MessageInfo> o) {
|
||||
// 后端采用异步最终一致,详情响应可能仍是加一前的值;稍后刷新列表读取最终值。
|
||||
if (o != null && o.data != null && o.data.getReadTimes() > messageInfo.getReadTimes()) {
|
||||
messageInfo.setReadTimes(o.data.getReadTimes());
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
activityNotifylistBinding.recyclerNofity.postDelayed(() -> getNotifyList(), 1200L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int code, String msg) {
|
||||
LogUtils.i("阅读次数上报失败 pushId=" + pushId + ", error=" + msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError2(Result<MessageInfo> o) {
|
||||
LogUtils.i("阅读次数上报失败 pushId=" + pushId);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 启用Edge-to-Edge模式(核心方法)
|
||||
*
|
||||
@@ -121,7 +158,7 @@ public class NotifyListActivity extends AppCompatActivity {
|
||||
|
||||
public void getNotifyList() {
|
||||
//通知列表
|
||||
Api.getInstance().getNotifyList(userId, page, 10)
|
||||
Api.getInstance().getNotifyList(userId, page, 10, 0)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new BaseObserver<>() {
|
||||
|
||||
@@ -10,8 +10,8 @@ plugins {
|
||||
|
||||
ext {
|
||||
outputPath = "${project.rootDir}/apks"
|
||||
versionCode = 131
|
||||
versionName = "v1.3.1"
|
||||
versionCode = 100
|
||||
versionName = "v1.0.0"
|
||||
namespace = "com.webclip.base"
|
||||
JAVA_VERSION = JavaVersion.VERSION_17
|
||||
}
|
||||
@@ -100,3 +100,5 @@ include ':JDCLUB9VIP'//158
|
||||
include ':ANTBET'//307
|
||||
include ':BOSSKU'//308
|
||||
include ':jpot9'//309
|
||||
include ':titanplayz'//310
|
||||
include ':amazy'//311
|
||||
2
titanplayz/.gitignore
vendored
Normal file
2
titanplayz/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/build
|
||||
/release
|
||||
93
titanplayz/build.gradle
Normal file
93
titanplayz/build.gradle
Normal file
@@ -0,0 +1,93 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'com.google.gms.google-services'
|
||||
}
|
||||
|
||||
def appOutPutName = "FlyDragon"
|
||||
|
||||
android {
|
||||
namespace rootProject.ext.namespace
|
||||
compileSdk 36
|
||||
defaultConfig {
|
||||
minSdkVersion 24
|
||||
targetSdk 36
|
||||
versionCode rootProject.ext.versionCode
|
||||
versionName rootProject.ext.versionName
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
applicationId "com.sbadab.FlyDragon"
|
||||
|
||||
//app大背景色
|
||||
resValue('color', 'windows_color', '#000000')
|
||||
//底部导航栏颜色 大背景颜色为 windows_color——style_color的上下渐变色
|
||||
resValue('color', 'style_color', '#000000')
|
||||
//app 名字
|
||||
resValue('string', 'app_name', 'FlyDragon')
|
||||
|
||||
|
||||
buildConfigField "String", "BASE_URL", "\"https://live22x.com/\""
|
||||
buildConfigField "int", "USERID", "310"
|
||||
buildConfigField "boolean", "IS_WHITE", "false"
|
||||
buildConfigField "boolean", "IS_ROUND", "true"
|
||||
buildConfigField "int", "ROUND_RADIUS", "10"
|
||||
buildConfigField "boolean", "HAS_CONTACT", "true"
|
||||
buildConfigField "boolean", "HAS_HOOK", "false"
|
||||
|
||||
}
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
debug {
|
||||
storeFile file('telur33.jks')
|
||||
storePassword "android2014"
|
||||
keyAlias 'key0'
|
||||
keyPassword "android2014"
|
||||
}
|
||||
release {
|
||||
storeFile file('telur33.jks')
|
||||
storePassword "android2014"
|
||||
keyAlias 'key0'
|
||||
keyPassword "android2014"
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility rootProject.ext.JAVA_VERSION
|
||||
targetCompatibility rootProject.ext.JAVA_VERSION
|
||||
}
|
||||
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.all {
|
||||
def outputDir = new File(rootProject.ext.outputPath)
|
||||
outputDir.mkdirs()
|
||||
def outputFileName = "${appOutPutName}.apk"
|
||||
setOutputFileName(outputFileName)
|
||||
def newOutputFile = new File(outputDir, outputFileName)
|
||||
newOutputFile.parentFile.mkdirs()
|
||||
variant.assemble.doLast {
|
||||
try {
|
||||
java.nio.file.Files.copy(
|
||||
outputFile.toPath(),
|
||||
newOutputFile.toPath(),
|
||||
java.nio.file.StandardCopyOption.REPLACE_EXISTING
|
||||
)
|
||||
} catch (java.io.IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(path: ':base')
|
||||
}
|
||||
29
titanplayz/google-services.json
Normal file
29
titanplayz/google-services.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"project_info": {
|
||||
"project_number": "546127961982",
|
||||
"project_id": "titanplayz-a2589",
|
||||
"storage_bucket": "titanplayz-a2589.firebasestorage.app"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:546127961982:android:7a3eaeeee14fb134519d2f",
|
||||
"android_client_info": {
|
||||
"package_name": "com.sbadab.FlyDragon"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyDTG90A20wZnkpFqez0Ohr7J-OnRMc9y-U"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
||||
BIN
titanplayz/justlet.jks
Normal file
BIN
titanplayz/justlet.jks
Normal file
Binary file not shown.
32
titanplayz/proguard-rules.pro
vendored
Normal file
32
titanplayz/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
-dontwarn dalvik.**
|
||||
-dontwarn com.tencent.smtt.**
|
||||
|
||||
-keep class com.tencent.smtt.** {
|
||||
*;
|
||||
}
|
||||
|
||||
-keep class com.tencent.tbs.** {
|
||||
*;
|
||||
}
|
||||
67
titanplayz/src/main/AndroidManifest.xml
Normal file
67
titanplayz/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- <uses-permission android:name="android.permission.READ_CONTACTS" />-->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
|
||||
<!-- 8.0+系统需要-->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<!--推送权限-->
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<application
|
||||
android:name=".WebApplication"
|
||||
android:allowBackup="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:icon="@mipmap/app_logo"
|
||||
android:label="@string/app_name"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:roundIcon="@mipmap/app_logo"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.AppTheme"
|
||||
android:usesCleartextTraffic="true">
|
||||
|
||||
|
||||
<activity
|
||||
android:name=".IndexActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:exported="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:theme="@style/AppThemeStart">
|
||||
|
||||
<intent-filter>
|
||||
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
|
||||
<service
|
||||
android:name=".MyFirebaseMessageingService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||
android:resource="@mipmap/app_logo" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_color"
|
||||
android:resource="@color/notify_color" />
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_channel_id"
|
||||
android:value="@string/app_name" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
79
titanplayz/src/main/java/com/webclip/base/IndexActivity.java
Normal file
79
titanplayz/src/main/java/com/webclip/base/IndexActivity.java
Normal file
@@ -0,0 +1,79 @@
|
||||
package com.webclip.base;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.google.firebase.messaging.FirebaseMessaging;
|
||||
|
||||
public class IndexActivity extends MainActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
initConfig();
|
||||
super.onCreate(savedInstanceState);
|
||||
initWinwdowLogoConfig();
|
||||
// registerFCM();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void regFcm() {
|
||||
super.regFcm();
|
||||
registerFCM();
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册FCM
|
||||
*/
|
||||
private void registerFCM() {
|
||||
//订阅主题
|
||||
LogUtils.i("支持FCM 去注册");
|
||||
try {
|
||||
FirebaseMessaging.getInstance().subscribeToTopic("demo")
|
||||
.addOnCompleteListener(task -> {
|
||||
String msg = "Subscribed";
|
||||
if (!task.isSuccessful()) {
|
||||
msg = "Subscribe failed";
|
||||
}else{
|
||||
checkNotify();
|
||||
}
|
||||
LogUtils.i("支持FCM 结果:"+msg);
|
||||
});
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
LogUtils.i("支持FCM Exception");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于修改大背景渐变色 不设置
|
||||
*/
|
||||
private void initWinwdowLogoConfig() {
|
||||
//全局大背景 一个上下渐变 不要动
|
||||
setBackDrawables(R.drawable.big_bg);
|
||||
setImageView(BuildConfig.IS_ROUND,BuildConfig.ROUND_RADIUS);
|
||||
getWindow().getDecorView().setBackgroundResource(R.drawable.big_bg);
|
||||
|
||||
//需要修改启动页logo在这里弄 一般启动页logo就是app_logo 没特殊要求 不要动
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础配置都在这里
|
||||
* 不要动
|
||||
*/
|
||||
private void initConfig() {
|
||||
|
||||
//===========================以下是APP的配置信息 都写在 app_config.xml中==================================
|
||||
userId = BuildConfig.USERID;
|
||||
saveInt(IndexActivity.this,"user_code",userId);
|
||||
|
||||
saveString(this, "base_url",BuildConfig.BASE_URL);
|
||||
styleColor = getColor(R.color.style_color);
|
||||
windowsColor = getColor(R.color.windows_color);
|
||||
isWhite = BuildConfig.IS_WHITE;
|
||||
hasContact = BuildConfig.HAS_CONTACT;
|
||||
hasHook = BuildConfig.HAS_HOOK;
|
||||
|
||||
//===========================以上是APP的配置信息 都写在 app_config.xml中==================================
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.webclip.base;
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import com.google.firebase.messaging.FirebaseMessagingService;
|
||||
import com.google.firebase.messaging.RemoteMessage;
|
||||
import com.google.gson.Gson;
|
||||
import com.webclip.base.GsonUtils;
|
||||
import com.webclip.base.MessageInfo;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
public class MyFirebaseMessageingService extends FirebaseMessagingService {
|
||||
|
||||
public MyFirebaseMessageingService() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
|
||||
super.onMessageReceived(remoteMessage);
|
||||
Map<String, String> serviceData = remoteMessage.getData(); //后台推送数据
|
||||
if (serviceData != null && serviceData.containsKey("message")) {
|
||||
String value = serviceData.get("message");
|
||||
Gson gson = new Gson();
|
||||
MessageInfo messageInfo = gson.fromJson(value, MessageInfo.class);
|
||||
showNotification(messageInfo);
|
||||
} else {
|
||||
//收到通知 创建notify
|
||||
if (remoteMessage.getNotification() != null) {
|
||||
showNotification(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showNotification(MessageInfo messageInfo) {
|
||||
Intent notifyIntent = new Intent(this, IndexActivity.class);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE) {
|
||||
ComponentName launchComponent = null;
|
||||
launchComponent = getApplication()
|
||||
.getPackageManager()
|
||||
.getLaunchIntentForPackage(getApplication().getPackageName())
|
||||
.getComponent();
|
||||
notifyIntent.setComponent(launchComponent);
|
||||
}
|
||||
notifyIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
notifyIntent.setAction(Intent.ACTION_VIEW);
|
||||
notifyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 必须
|
||||
notifyIntent.putExtra("message", messageInfo);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, new Random().nextInt(10000), notifyIntent, PendingIntent.FLAG_IMMUTABLE);
|
||||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
NotificationChannel channelwinway = null;
|
||||
NotificationCompat.Builder notificationBuilder = null;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
channelwinway = new NotificationChannel(getString(R.string.app_name), "notify", NotificationManager.IMPORTANCE_DEFAULT);
|
||||
channelwinway.enableLights(true);
|
||||
channelwinway.enableVibration(true);
|
||||
notificationManager.createNotificationChannel(channelwinway);
|
||||
notificationBuilder = new NotificationCompat.Builder(this, channelwinway.getId())
|
||||
.setSmallIcon(R.mipmap.app_logo)
|
||||
.setContentTitle(messageInfo.getTitle())
|
||||
.setContentText(messageInfo.getContent())
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntent);
|
||||
} else {
|
||||
notificationBuilder = new NotificationCompat.Builder(this, getString(R.string.app_name))
|
||||
.setSmallIcon(R.mipmap.app_logo)
|
||||
.setContentTitle(messageInfo.getTitle())
|
||||
.setContentText(messageInfo.getContent())
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntent);
|
||||
}
|
||||
notificationManager.notify(0, notificationBuilder.build());
|
||||
}
|
||||
|
||||
private void showNotification(String title, String body) {
|
||||
Intent notifyIntent = new Intent(this, IndexActivity.class);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.CUPCAKE) {
|
||||
ComponentName launchComponent = null;
|
||||
launchComponent = getApplication()
|
||||
.getPackageManager()
|
||||
.getLaunchIntentForPackage(getApplication().getPackageName())
|
||||
.getComponent();
|
||||
notifyIntent.setComponent(launchComponent);
|
||||
}
|
||||
notifyIntent.putExtra("message", body);
|
||||
notifyIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
notifyIntent.setAction(Intent.ACTION_VIEW);
|
||||
notifyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 必须
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, new Random().nextInt(10000), notifyIntent, PendingIntent.FLAG_IMMUTABLE);
|
||||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
NotificationChannel channelwinway = null;
|
||||
NotificationCompat.Builder notificationBuilder = null;
|
||||
MessageInfo messageInfo = GsonUtils.getObjFromJSON(body, MessageInfo.class);
|
||||
if (messageInfo != null) {
|
||||
body = messageInfo.getContent();
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
channelwinway = new NotificationChannel(getString(R.string.app_name), "notify", NotificationManager.IMPORTANCE_DEFAULT);
|
||||
channelwinway.enableLights(true);
|
||||
channelwinway.enableVibration(true);
|
||||
notificationManager.createNotificationChannel(channelwinway);
|
||||
notificationBuilder = new NotificationCompat.Builder(this, channelwinway.getId())
|
||||
.setSmallIcon(R.mipmap.app_logo)
|
||||
.setContentTitle(title)
|
||||
.setContentText(body)
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntent);
|
||||
} else {
|
||||
notificationBuilder = new NotificationCompat.Builder(this, getString(R.string.app_name))
|
||||
.setSmallIcon(R.mipmap.app_logo)
|
||||
.setContentTitle(title)
|
||||
.setContentText(body)
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntent);
|
||||
}
|
||||
notificationManager.notify(0, notificationBuilder.build());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.webclip.base;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import com.webclip.base.LogUtils;
|
||||
|
||||
public class WebApplication extends Application {
|
||||
|
||||
|
||||
public static Context application;
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
// 设置开启优化方案
|
||||
application = this;
|
||||
LogUtils.isDebug = BuildConfig.BUILD_TYPE.equals("debug");
|
||||
}
|
||||
}
|
||||
9
titanplayz/src/main/res/drawable/big_bg.xml
Normal file
9
titanplayz/src/main/res/drawable/big_bg.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:angle="270"
|
||||
android:startColor="@color/windows_color"
|
||||
android:centerColor="@color/windows_color"
|
||||
android:endColor="@color/style_color"/>
|
||||
</shape>
|
||||
BIN
titanplayz/src/main/res/mipmap-xxhdpi/app_logo.png
Normal file
BIN
titanplayz/src/main/res/mipmap-xxhdpi/app_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
91
titanplayz/src/main/res/values/themes.xml
Normal file
91
titanplayz/src/main/res/values/themes.xml
Normal file
@@ -0,0 +1,91 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar.Bridge">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/purple_500</item>
|
||||
<item name="colorPrimaryVariant">@color/purple_700</item>
|
||||
<item name="colorOnPrimary">@color/white</item>
|
||||
<!-- Secondary brand color. -->
|
||||
<item name="colorSecondary">@color/teal_200</item>
|
||||
<item name="colorSecondaryVariant">@color/teal_700</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="android:windowBackground">#000000</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Theme.Calculcator1" parent="Theme.MaterialComponents.DayNight.DarkActionBar.Bridge">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/purple_500</item>
|
||||
<item name="colorPrimaryVariant">@color/purple_700</item>
|
||||
<item name="colorOnPrimary">@color/white</item>
|
||||
<!-- Secondary brand color. -->
|
||||
<item name="colorSecondary">@color/teal_200</item>
|
||||
<item name="colorSecondaryVariant">@color/teal_700</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<item name="android:windowFullscreen">true</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
|
||||
|
||||
<declare-styleable name="CircleImageView">
|
||||
<attr name="ease_border_color" format="color" />
|
||||
<attr name="ease_border_width" format="dimension" />
|
||||
<attr name="ease_press_alpha" format="integer" />
|
||||
<attr name="ease_press_color" format="color" />
|
||||
<attr name="ease_radius" format="dimension" />
|
||||
<attr name="es_shape_type" format="enum">
|
||||
<enum name="none" value="0" />
|
||||
<enum name="round" value="1" />
|
||||
<enum name="rectangle" value="2" />
|
||||
</attr>
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
<!-- 注意:当前AppTheme主题,在values-v23中单独重复维护。原因是Android 6以下系统不支持设置
|
||||
系统状态栏颜色,如果按照设计,状态栏使用素色则在android6以下手机上就看不清系统状态栏文字了(
|
||||
因为系统文字是白色)。在values-v23表示当Android 23(即android 6)及以上版本将自动使用该目录
|
||||
下的主题(即 colorPrimaryDark 使用素色,从而跟标题栏颜色保持一致,实现沉浸式ui效果)。-->
|
||||
<style name="AppThemeStart" parent="@style/Theme.AppCompat.Light.NoActionBar">
|
||||
<item name="android:windowTranslucentStatus">false</item>
|
||||
<item name="android:windowTranslucentNavigation">false</item>
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="colorPrimary">@color/windows_color</item>
|
||||
<item name="colorPrimaryDark">@color/windows_color</item>
|
||||
<item name="colorAccent">@color/windows_color</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<!-- 隐藏Activity窗口的Title标题栏 -->
|
||||
<item name="windowNoTitle">true</item>
|
||||
<!-- <item name="android:windowFullscreen">true</item>-->
|
||||
<!-- <item name="android:windowBackground">@drawable/splah_bg</item>-->
|
||||
|
||||
<item name="android:navigationBarColor">@color/style_color</item>
|
||||
<!-- <item name="android:windowBackground">@mipmap/big_bg</item>-->
|
||||
<item name="android:forceDarkAllowed" tools:ignore="NewApi">false</item>
|
||||
<item name="android:windowBackground">@drawable/big_bg</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="MaterialDesignDialog" parent="@style/Theme.AppCompat.Dialog">
|
||||
<!-- 背景透明 -->
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<!-- 浮于Activity之上 -->
|
||||
<item name="android:windowIsFloating">true</item>
|
||||
<!-- 边框 -->
|
||||
<item name="android:windowFrame">@null</item>
|
||||
<!-- Dialog以外的区域模糊效果 -->
|
||||
<item name="android:backgroundDimEnabled">true</item>
|
||||
<!-- 无标题 -->
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<!-- 半透明 -->
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:windowCloseOnTouchOutside">true</item>
|
||||
</style>
|
||||
</resources>
|
||||
10
titanplayz/src/main/res/xml/app_updater_paths.xml
Normal file
10
titanplayz/src/main/res/xml/app_updater_paths.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths>
|
||||
<root-path name="app_root_path" path="/"/>
|
||||
<external-path name="app_external_path" path="/"/>
|
||||
<external-cache-path name="app_external_cache_path" path="/"/>
|
||||
<external-files-path name="app_external_files_path" path="/"/>
|
||||
<files-path name="app_files_path" path="/"/>
|
||||
<cache-path name="app_cache_path" path="/"/>
|
||||
|
||||
</paths>
|
||||
4
titanplayz/src/main/res/xml/network_security_config.xml
Normal file
4
titanplayz/src/main/res/xml/network_security_config.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<base-config cleartextTrafficPermitted="true" />
|
||||
</network-security-config>
|
||||
13
titanplayz/src/main/res/xml/provider_paths.xml
Normal file
13
titanplayz/src/main/res/xml/provider_paths.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding= "utf-8"?>
|
||||
<resources>
|
||||
<paths >
|
||||
<external-path name="external_files" path="."/>
|
||||
<root-path name="root" path="." />
|
||||
<files-path name="files" path="." />
|
||||
<cache-path name="cache" path="." />
|
||||
<external-files-path name="external_files_f" path="." />
|
||||
<external-cache-path name="external_cache" path="." />
|
||||
</paths >
|
||||
</resources>
|
||||
<!-- 适配7.0及其以上,配合com.eva.android.OpenFileUtil,用于解决调用系统Intent查看大文件内
|
||||
容、拍照保存图片的功能时出现"android.os.FileUriExposedException"异常的问题 -->
|
||||
BIN
titanplayz/telur33.jks
Normal file
BIN
titanplayz/telur33.jks
Normal file
Binary file not shown.
Reference in New Issue
Block a user