diff --git a/app/build.gradle b/app/build.gradle index 2d914004c8..88120c990c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -330,6 +330,8 @@ dependencies { }) implementation "com.github.PhilJay:MPAndroidChart:${chart}" + implementation "com.lahm.library:easy-protector-release:${easyProtector}" + implementation "com.github.hsiafan:apk-parser:${apkParser}" implementation "org.nanohttpd:nanohttpd:${nanohttpd}" diff --git a/app/src/main/java/com/gh/common/constant/Constants.java b/app/src/main/java/com/gh/common/constant/Constants.java index dbac628820..528297453b 100644 --- a/app/src/main/java/com/gh/common/constant/Constants.java +++ b/app/src/main/java/com/gh/common/constant/Constants.java @@ -216,6 +216,8 @@ public class Constants { // 用户是否需要 weibo x86 so public static final String SP_USER_NEED_WEIBO_X86_SO = "user_need_weibo_x86_so"; + // 当前设备是不是模拟器 + public static final String SP_IS_EMULATOR = "is_emulator"; // 内容视频播放选项 public static final String SP_CONTENT_VIDEO_OPTION = "content_video_option"; diff --git a/app/src/main/java/com/gh/common/util/DialogHelper.kt b/app/src/main/java/com/gh/common/util/DialogHelper.kt index ef992d3326..b121dfc650 100644 --- a/app/src/main/java/com/gh/common/util/DialogHelper.kt +++ b/app/src/main/java/com/gh/common/util/DialogHelper.kt @@ -26,6 +26,7 @@ object DialogHelper { * * uiModificationCallback,可用来手动微调样式的回调,可使用 binding 来修改颜色、文字大小等 */ + // TODO 提供 dismiss callback fun showDialog( context: Context, title: String, @@ -38,10 +39,10 @@ object DialogHelper { uiModificationCallback: ((binding: DialogAlertDefaultBinding) -> Unit)? = null, trackMtaEvent: Boolean = false, mtaEvent: String = "", - mtaKey: String = "") { + mtaKey: String = ""): Dialog? { val solidContext = checkDialogContext(context) - if (solidContext is Activity && solidContext.isFinishing) return + if (solidContext is Activity && solidContext.isFinishing) return null val dialog = if (trackMtaEvent) { TrackableDialog(solidContext, R.style.GhAlertDialog, mtaEvent, mtaKey) @@ -103,6 +104,8 @@ object DialogHelper { dialog.setContentView(contentView) dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) dialog.show() + + return dialog } /** diff --git a/app/src/main/java/com/gh/common/util/EmulatorUtil.java b/app/src/main/java/com/gh/common/util/EmulatorUtil.java new file mode 100644 index 0000000000..8c21f12ab9 --- /dev/null +++ b/app/src/main/java/com/gh/common/util/EmulatorUtil.java @@ -0,0 +1,378 @@ +package com.gh.common.util; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.net.Uri; +import android.text.TextUtils; + +import com.gh.common.constant.Constants; +import com.lahm.library.CheckResult; +import com.lahm.library.CommandUtil; + +import static android.content.Context.SENSOR_SERVICE; +import static com.lahm.library.CheckResult.RESULT_EMULATOR; +import static com.lahm.library.CheckResult.RESULT_MAYBE_EMULATOR; +import static com.lahm.library.CheckResult.RESULT_UNKNOWN; + +public class EmulatorUtil { + + private SimpleCallback mCallback; + + private EmulatorUtil() { + + } + + private static class SingletonHolder { + private static final EmulatorUtil INSTANCE = new EmulatorUtil(); + } + + public static EmulatorUtil getSingleInstance() { + return SingletonHolder.INSTANCE; + } + + public void readSysProperty(Context context, SimpleCallback callback) { + if (context == null) + throw new IllegalArgumentException("context must not be null"); + + mCallback = callback; + + int suspectCount = 0; + + //检测硬件名称 + CheckResult hardwareResult = checkFeaturesByHardware(); + switch (hardwareResult.result) { + case RESULT_MAYBE_EMULATOR: + ++suspectCount; + break; + case RESULT_EMULATOR: + mCallback.onCallback(true); + return; + } + + //检测渠道 + CheckResult flavorResult = checkFeaturesByFlavor(); + switch (flavorResult.result) { + case RESULT_MAYBE_EMULATOR: + ++suspectCount; + break; + case RESULT_EMULATOR: + mCallback.onCallback(true); + return; + } + + //检测设备型号 + CheckResult modelResult = checkFeaturesByModel(); + switch (modelResult.result) { + case RESULT_MAYBE_EMULATOR: + ++suspectCount; + break; + case RESULT_EMULATOR: + mCallback.onCallback(true); + return; + } + + //检测硬件制造商 + CheckResult manufacturerResult = checkFeaturesByManufacturer(); + switch (manufacturerResult.result) { + case RESULT_MAYBE_EMULATOR: + ++suspectCount; + break; + case RESULT_EMULATOR: + mCallback.onCallback(true); + return; + } + + //检测主板名称 + CheckResult boardResult = checkFeaturesByBoard(); + switch (boardResult.result) { + case RESULT_MAYBE_EMULATOR: + ++suspectCount; + break; + case RESULT_EMULATOR: + mCallback.onCallback(true); + return; + } + + //检测主板平台 + CheckResult platformResult = checkFeaturesByPlatform(); + switch (platformResult.result) { + case RESULT_MAYBE_EMULATOR: + ++suspectCount; + break; + case RESULT_EMULATOR: + mCallback.onCallback(true); + return; + } + + //检测基带信息 + CheckResult baseBandResult = checkFeaturesByBaseBand(); + switch (baseBandResult.result) { + case RESULT_MAYBE_EMULATOR: + suspectCount += 2;//模拟器基带信息为null的情况概率相当大 + break; + case RESULT_EMULATOR: + mCallback.onCallback(true); + return; + } + + //检测传感器数量 + int sensorNumber = getSensorNumber(context); + if (sensorNumber <= 7) ++suspectCount; + + //检测是否支持闪光灯 + boolean supportCameraFlash = supportCameraFlash(context); + if (!supportCameraFlash) ++suspectCount; + //检测是否支持相机 + boolean supportCamera = supportCamera(context); + if (!supportCamera) ++suspectCount; + //检测是否支持蓝牙 + boolean supportBluetooth = supportBluetooth(context); + if (!supportBluetooth) ++suspectCount; + + //检测光线传感器 + boolean hasLightSensor = hasLightSensor(context); + if (!hasLightSensor) ++suspectCount; + + //检测进程组信息 + CheckResult cgroupResult = checkFeaturesByCgroup(); + if (cgroupResult.result == RESULT_MAYBE_EMULATOR) ++suspectCount; + + if (suspectCount > 3) { + mCallback.onCallback(true); + return; + } + // 如果有陀螺仪传感器就根据陀螺仪传感器数值判断,因为模拟器的陀螺仪数值都是0.0 + checkGyroscopeSensor(context); + } + + private String getProperty(String propName) { + String property = CommandUtil.getSingleInstance().getProperty(propName); + return TextUtils.isEmpty(property) ? null : property; + } + + /** + * 特征参数-硬件名称 + * + * @return 0表示可能是模拟器,1表示模拟器,2表示可能是真机 + */ + private CheckResult checkFeaturesByHardware() { + String hardware = getProperty("ro.hardware"); + if (null == hardware) return new CheckResult(RESULT_MAYBE_EMULATOR, null); + int result; + String tempValue = hardware.toLowerCase(); + switch (tempValue) { + case "ttvm"://天天模拟器 + case "nox"://夜神模拟器 + case "cancro"://网易MUMU模拟器 + case "intel"://逍遥模拟器 + case "vbox": + case "vbox86"://腾讯手游助手 + case "android_x86"://雷电模拟器 + result = RESULT_EMULATOR; + break; + default: + result = RESULT_UNKNOWN; + break; + } + return new CheckResult(result, hardware); + } + + /** + * 特征参数-渠道 + * + * @return 0表示可能是模拟器,1表示模拟器,2表示可能是真机 + */ + private CheckResult checkFeaturesByFlavor() { + String flavor = getProperty("ro.build.flavor"); + if (null == flavor) return new CheckResult(RESULT_MAYBE_EMULATOR, null); + int result; + String tempValue = flavor.toLowerCase(); + if (tempValue.contains("vbox")) result = RESULT_EMULATOR; + else if (tempValue.contains("sdk_gphone")) result = RESULT_EMULATOR; + else result = RESULT_UNKNOWN; + return new CheckResult(result, flavor); + } + + /** + * 特征参数-设备型号 + * + * @return 0表示可能是模拟器,1表示模拟器,2表示可能是真机 + */ + private CheckResult checkFeaturesByModel() { + String model = getProperty("ro.product.model"); + if (null == model) return new CheckResult(RESULT_MAYBE_EMULATOR, null); + int result; + String tempValue = model.toLowerCase(); + if (tempValue.contains("google_sdk")) result = RESULT_EMULATOR; + else if (tempValue.contains("emulator")) result = RESULT_EMULATOR; + else if (tempValue.contains("android sdk built for x86")) result = RESULT_EMULATOR; + else result = RESULT_UNKNOWN; + return new CheckResult(result, model); + } + + /** + * 特征参数-硬件制造商 + * + * @return 0表示可能是模拟器,1表示模拟器,2表示可能是真机 + */ + private CheckResult checkFeaturesByManufacturer() { + String manufacturer = getProperty("ro.product.manufacturer"); + if (null == manufacturer) return new CheckResult(RESULT_MAYBE_EMULATOR, null); + int result; + String tempValue = manufacturer.toLowerCase(); + if (tempValue.contains("genymotion")) result = RESULT_EMULATOR; + else if (tempValue.contains("netease")) result = RESULT_EMULATOR;//网易MUMU模拟器 + else result = RESULT_UNKNOWN; + return new CheckResult(result, manufacturer); + } + + /** + * 特征参数-主板名称 + * + * @return 0表示可能是模拟器,1表示模拟器,2表示可能是真机 + */ + private CheckResult checkFeaturesByBoard() { + String board = getProperty("ro.product.board"); + if (null == board) return new CheckResult(RESULT_MAYBE_EMULATOR, null); + int result; + String tempValue = board.toLowerCase(); + if (tempValue.contains("android")) result = RESULT_EMULATOR; + else if (tempValue.contains("goldfish")) result = RESULT_EMULATOR; + else result = RESULT_UNKNOWN; + return new CheckResult(result, board); + } + + /** + * 特征参数-主板平台 + * + * @return 0表示可能是模拟器,1表示模拟器,2表示可能是真机 + */ + private CheckResult checkFeaturesByPlatform() { + String platform = getProperty("ro.board.platform"); + if (null == platform) return new CheckResult(RESULT_MAYBE_EMULATOR, null); + int result; + String tempValue = platform.toLowerCase(); + if (tempValue.contains("android")) result = RESULT_EMULATOR; + else result = RESULT_UNKNOWN; + return new CheckResult(result, platform); + } + + /** + * 特征参数-基带信息 + * + * @return 0表示可能是模拟器,1表示模拟器,2表示可能是真机 + */ + private CheckResult checkFeaturesByBaseBand() { + String baseBandVersion = getProperty("gsm.version.baseband"); + if (null == baseBandVersion) return new CheckResult(RESULT_MAYBE_EMULATOR, null); + int result; + if (baseBandVersion.contains("1.0.0.0")) result = RESULT_EMULATOR; + else result = RESULT_UNKNOWN; + return new CheckResult(result, baseBandVersion); + } + + /** + * 获取传感器数量 + */ + private int getSensorNumber(Context context) { + SensorManager sm = (SensorManager) context.getSystemService(SENSOR_SERVICE); + return sm.getSensorList(Sensor.TYPE_ALL).size(); + } + + /** + * 是否支持相机 + */ + private boolean supportCamera(Context context) { + return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA); + } + + /** + * 是否支持闪光灯 + */ + private boolean supportCameraFlash(Context context) { + return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH); + } + + /** + * 是否支持蓝牙 + */ + private boolean supportBluetooth(Context context) { + return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH); + } + + /** + * 判断是否存在光传感器来判断是否为模拟器 + * 部分真机也不存在温度和压力传感器。其余传感器模拟器也存在。 + * + * @return false为模拟器 + */ + private boolean hasLightSensor(Context context) { + SensorManager sensorManager = (SensorManager) context.getSystemService(SENSOR_SERVICE); + Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); //光线传感器 + if (null == sensor) return false; + else return true; + } + + /** + * 特征参数-进程组信息 + */ + private CheckResult checkFeaturesByCgroup() { + String filter = CommandUtil.getSingleInstance().exec("cat /proc/self/cgroup"); + if (null == filter) return new CheckResult(RESULT_MAYBE_EMULATOR, null); + return new CheckResult(RESULT_UNKNOWN, filter); + } + + /** + * 检查是否可以拨打电话和发短信 + */ + private void checkCallPhone(Context context) { + try { + Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:123456")); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + Intent intent2 = new Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:123456")); + intent2.putExtra("sms_body", "test"); + + if (intent.resolveActivity(context.getPackageManager()) == null || intent2.resolveActivity(context.getPackageManager()) == null) { + mCallback.onCallback(true); + } + } catch (Exception ignore) { + } + } + + private void checkGyroscopeSensor(Context context) { + SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); + SensorEventListener listener = new SensorEventListener() { + int changeTimes = 0; + int zeroTimes = 0; + + @Override + public void onSensorChanged(SensorEvent event) { + changeTimes++; + if (event.values[0] == 0.0 && event.values[1] == 0.0 && event.values[2] == 0.0) { + zeroTimes++; + } + if (changeTimes > 50) { + if (changeTimes == zeroTimes) { + checkCallPhone(context); + } + sensorManager.unregisterListener(this); + } + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + + } + }; + Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); + if (sensor != null) { + sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_FASTEST); + } + } +} diff --git a/app/src/main/java/com/gh/common/util/EntranceUtils.java b/app/src/main/java/com/gh/common/util/EntranceUtils.java index 5eeb5c2385..ec744161fc 100644 --- a/app/src/main/java/com/gh/common/util/EntranceUtils.java +++ b/app/src/main/java/com/gh/common/util/EntranceUtils.java @@ -238,7 +238,8 @@ public class EntranceUtils { public static final String KEY_CATEGORY_LIST = "categoty_list"; public static final String KEY_IS_FREE = "is_free"; public static final String KEY_IS_SIGN = "is_sign"; - public static final String KEY_IS_FORCED_TO_CERTICIFICE = "is_forced_to_certificate"; + public static final String KEY_IS_FORCED_TO_CERTIFICATE = "is_forced_to_certificate"; + public static final String KEY_IS_FORCED_TO_CERTIFICATE_BUT_WITH_BACKDOOR = "is_forced_to_certificate_but_with_backdoor"; public static final String KEY_IS_CHOOSE_APK = "is_choose_apk"; public static final String KEY_TAB_INDEX = "tab_index"; public static final String KEY_IS_CATEGORY_V2 = "is_category_v2"; diff --git a/app/src/main/java/com/gh/common/util/RealNameHelper.kt b/app/src/main/java/com/gh/common/util/RealNameHelper.kt index b15d4e0bc9..9b2b2ee20d 100644 --- a/app/src/main/java/com/gh/common/util/RealNameHelper.kt +++ b/app/src/main/java/com/gh/common/util/RealNameHelper.kt @@ -22,6 +22,8 @@ object RealNameHelper { * 弹未成年人不能下载游戏弹窗 */ fun showRealNameUnqualifiedDialog(downloadEntity: DownloadEntity) { + // 是否强制实名 + val isForced = downloadEntity.getMetaExtra("force_real_name") != "false" val contentText = if (downloadEntity.status == DownloadStatus.done) { "为保护未成年身心健康成长\n" + "根据相关政策要求,该游戏不对未成年人开放" @@ -55,6 +57,9 @@ object RealNameHelper { * 弹需要实名弹窗 */ fun showRealNameUncertificatedDialog(downloadEntity: DownloadEntity) { + // 是否强制实名 + val isForced = downloadEntity.getMetaExtra("force_real_name") != "false" + NewLogUtils.logCertificationTrigger(downloadEntity.gameId, downloadEntity.name) val contentText = if (downloadEntity.status == DownloadStatus.done) { @@ -68,7 +73,7 @@ object RealNameHelper { ToastUtils.toast("为保护未成年身心健康成长,根据相关政策要求,该游戏不对未成年人开放") } else { NewLogUtils.logCertificationHintDialogAppearance() - DialogHelper.showDialog( + val dialog = DialogHelper.showDialog( currentActivity, title = "实名提示", content = contentText, @@ -80,7 +85,8 @@ object RealNameHelper { currentActivity, ShellActivity.Type.REAL_NAME_INFO ).apply { - putExtra(EntranceUtils.KEY_IS_FORCED_TO_CERTICIFICE, true) + putExtra(EntranceUtils.KEY_IS_FORCED_TO_CERTIFICATE, true) + putExtra(EntranceUtils.KEY_IS_FORCED_TO_CERTIFICATE_BUT_WITH_BACKDOOR, !isForced) } ) if (downloadEntity.status == DownloadStatus.done) { @@ -90,8 +96,20 @@ object RealNameHelper { }, cancelClickCallback = { NewLogUtils.logCertificationHintDialogOptionsClicked("取消") + if (!isForced) { + DownloadManager.getInstance(HaloApp.getInstance()) + .resumeAllInvisiblePendingTask() + } } ) + + dialog?.setOnCancelListener { + NewLogUtils.logCertificationHintDialogOptionsClicked("取消") + if (!isForced) { + DownloadManager.getInstance(HaloApp.getInstance()) + .resumeAllInvisiblePendingTask() + } + } } if (downloadEntity.status != DownloadStatus.done) { diff --git a/app/src/main/java/com/gh/common/util/UploadImageUtils.kt b/app/src/main/java/com/gh/common/util/UploadImageUtils.kt index 0187815a19..16bdf7ba8b 100644 --- a/app/src/main/java/com/gh/common/util/UploadImageUtils.kt +++ b/app/src/main/java/com/gh/common/util/UploadImageUtils.kt @@ -21,7 +21,6 @@ import java.io.File import java.net.URLEncoder import java.util.* import kotlin.collections.HashMap -import java.lang.Exception object UploadImageUtils { @@ -35,6 +34,7 @@ object UploadImageUtils { poster, game_upload, user_background, + id_photo, comment } diff --git a/app/src/main/java/com/gh/download/DownloadManager.java b/app/src/main/java/com/gh/download/DownloadManager.java index 2c58b82a6c..b48d410170 100644 --- a/app/src/main/java/com/gh/download/DownloadManager.java +++ b/app/src/main/java/com/gh/download/DownloadManager.java @@ -403,6 +403,12 @@ public class DownloadManager implements DownloadStatusListener { if (downloadEntity != null) { String url = downloadEntity.getUrl(); checkDownloadEntryRecordValidate(url); + + // 添加当前设备为模拟器的标签 + if (HaloApp.getInstance().isEmulator) { + downloadEntity.getMeta().put("isEmulator", "true"); + } + if (isDownloadCompleted(url)) { downloadEntity.setStatus(DownloadStatus.done); DataChanger.INSTANCE.notifyDataChanged(downloadEntity); @@ -1128,7 +1134,9 @@ public class DownloadManager implements DownloadStatusListener { */ public void resumeAllInvisiblePendingTask() { for (DownloadEntity task : mInvisiblePendingTaskList) { - add(task); + if ("false".equals(task.getMeta().get("force_real_name"))) { + add(task); + } } mInvisiblePendingTaskList.clear(); } diff --git a/app/src/main/java/com/gh/gamecenter/ShellActivity.kt b/app/src/main/java/com/gh/gamecenter/ShellActivity.kt index 2484e64853..1bd90e3061 100644 --- a/app/src/main/java/com/gh/gamecenter/ShellActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/ShellActivity.kt @@ -9,6 +9,7 @@ import com.gh.base.fragment.BaseFragment import com.gh.common.util.EntranceUtils import com.gh.gamecenter.amway.AmwaySuccessFragment import com.halo.assistant.fragment.SwitchInstallMethodFragment +import com.halo.assistant.fragment.user.ManuallyRealNameFragment import com.halo.assistant.fragment.user.RealNameInfoFragment /** @@ -32,6 +33,7 @@ class ShellActivity : ToolBarActivity() { Type.AMWAY_SUCCESS -> startFragment(AmwaySuccessFragment().with(bundle)) Type.SWITCH_INSTALL_METHOD -> startFragment(SwitchInstallMethodFragment()) Type.REAL_NAME_INFO -> startFragment(RealNameInfoFragment().with(bundle)) + Type.MANUALLY_REAL_NAME -> startFragment(ManuallyRealNameFragment().with(bundle?.getBundle(EntranceUtils.KEY_DATA))) } } @@ -57,7 +59,8 @@ class ShellActivity : ToolBarActivity() { enum class Type(val value: String) { AMWAY_SUCCESS("amway_success"), SWITCH_INSTALL_METHOD("switch_install_method"), - REAL_NAME_INFO("real_name_info"); + REAL_NAME_INFO("real_name_info"), + MANUALLY_REAL_NAME("manually_real_name"); companion object { fun fromString(typeString: String): Type { diff --git a/app/src/main/java/com/gh/gamecenter/UserInfoEditActivity.java b/app/src/main/java/com/gh/gamecenter/UserInfoEditActivity.java index c372b31e84..16136c0ae1 100644 --- a/app/src/main/java/com/gh/gamecenter/UserInfoEditActivity.java +++ b/app/src/main/java/com/gh/gamecenter/UserInfoEditActivity.java @@ -29,7 +29,7 @@ public class UserInfoEditActivity extends NormalActivity { public static Intent getIntent(Context context, String editType, Boolean isForcedToCertificate) { Bundle args = new Bundle(); args.putString(UserViewModel.KEY_EDIT_TYPE, editType); - args.putBoolean(EntranceUtils.KEY_IS_FORCED_TO_CERTICIFICE, isForcedToCertificate); + args.putBoolean(EntranceUtils.KEY_IS_FORCED_TO_CERTIFICATE, isForcedToCertificate); return getTargetIntent(context, UserInfoEditActivity.class, UserInfoEditFragment.class, args); } diff --git a/app/src/main/java/com/gh/gamecenter/entity/IdCardEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/IdCardEntity.kt index d36427fd57..8f2aad93ac 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/IdCardEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/IdCardEntity.kt @@ -1,10 +1,13 @@ package com.gh.gamecenter.entity import androidx.room.Entity +import com.google.gson.annotations.SerializedName @Entity data class IdCardEntity( var id: String? = null, var name: String? = null, var revise: Boolean? = false, + @SerializedName("id_photo") + var idPhoto: String? = null ) \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/game/vertical/GameVerticalAdapter.kt b/app/src/main/java/com/gh/gamecenter/game/vertical/GameVerticalAdapter.kt index 97cf99d575..ad02134cba 100644 --- a/app/src/main/java/com/gh/gamecenter/game/vertical/GameVerticalAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/game/vertical/GameVerticalAdapter.kt @@ -114,7 +114,7 @@ class GameVerticalAdapter( tempViewHolder.recommendTv = recommendTv tempViewHolder.recommendContainer = recommendConstraintLayout tempViewHolder.gameInfo = gameInfoGroup - tempViewHolder.gameServerType + tempViewHolder.gameServerType = serverTypeTv DownloadItemUtils.updateItem( mContext, diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java index 33b37fd8dc..8fc6bb8c5d 100644 --- a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java +++ b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java @@ -176,6 +176,12 @@ public interface ApiService { @POST("./certification:check") Single postCertificationCheck(@Body RequestBody body); + /** + * 实名认证人工审核 + */ + @POST("./certification:review") + Single postCertificationReview(@Body RequestBody body); + /** * 获取新闻详情 */ diff --git a/app/src/main/java/com/halo/assistant/HaloApp.java b/app/src/main/java/com/halo/assistant/HaloApp.java index 84e6335921..05174fd2ff 100644 --- a/app/src/main/java/com/halo/assistant/HaloApp.java +++ b/app/src/main/java/com/halo/assistant/HaloApp.java @@ -28,6 +28,7 @@ import com.gh.common.util.DeviceUtils; import com.gh.common.util.DownloadNotificationHelper; import com.gh.common.util.DownloadObserver; import com.gh.common.util.EnvHelper; +import com.gh.common.util.EmulatorUtil; import com.gh.common.util.HomeBottomBarHelper; import com.gh.common.util.ImageUtils; import com.gh.common.util.PackageHelper; @@ -77,6 +78,7 @@ public class HaloApp extends MultiDexApplication { public boolean isBrandNewInstall = false; // 当前用户是否是安装光环后第一次打开 public boolean isNewForThisVersion = false; // 当前用户是否是安装当前版本后第一次打开 (包括全新和更新) public boolean isRunningForeground = false; // 标记当前 APP 是否处于前台运行中 + public boolean isEmulator = false; // 当前设备是否为模拟器 public int mCacheKeyboardHeight = 0; @@ -210,30 +212,37 @@ public class HaloApp extends MultiDexApplication { if (initImmediately) { delay = 0; } - + postInit(delay); + + mIsPostInitialized = true; + } + + private void postInit(long delay) { AppExecutor.getUiExecutor().executeWithDelay(() -> { initThirdPartySdk(); - + DataUtils.getGid(); - + FixedRateJobHelper.begin(); RegionSettingHelper.getRegionSetting(); - + PackageRepository.initData(); - + // 刷新内存中的用户信息,避免应用进程重建时因没有用户信息数据而显示为掉登录状态 UserRepository.getInstance(this).getLoginUserInfo(); - + + checkIfDeviceIsEmulator(); + initReceiver(); initPackageChangesReceiver(); initConnectivityChangesReceiver(); - + initTimeConsumingAction(); - + // 注册回调以用于做各种统计 ProcessLifecycleOwner.get().getLifecycle().addObserver(new ProcessorLifeCycleOwner()); - + // 开发环境不要强制捕获相关异常,这些异常通常是需要处理的 if (!BuildConfig.DEBUG) { RxJavaPlugins.setErrorHandler(throwable -> { @@ -243,8 +252,6 @@ public class HaloApp extends MultiDexApplication { }); } }, delay); - - mIsPostInitialized = true; } private void initThirdPartySdk() { @@ -331,6 +338,21 @@ public class HaloApp extends MultiDexApplication { }); } + /** + * 检查当前设备是否为模拟器 + */ + private void checkIfDeviceIsEmulator() { + isEmulator = SPUtils.getBoolean(Constants.SP_IS_EMULATOR); + if (!isEmulator) { + EmulatorUtil.getSingleInstance().readSysProperty(HaloApp.getInstance().getApplication(), arg -> { + if (arg) { + SPUtils.setBoolean(Constants.SP_IS_EMULATOR, true); + isEmulator = true; + } + }); + } + } + public boolean isPostInitialized() { return mIsPostInitialized; } diff --git a/app/src/main/java/com/halo/assistant/fragment/user/ManuallyRealNameFragment.kt b/app/src/main/java/com/halo/assistant/fragment/user/ManuallyRealNameFragment.kt new file mode 100644 index 0000000000..caf616587c --- /dev/null +++ b/app/src/main/java/com/halo/assistant/fragment/user/ManuallyRealNameFragment.kt @@ -0,0 +1,199 @@ +package com.halo.assistant.fragment.user + +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.provider.MediaStore +import android.text.TextUtils +import android.view.View +import androidx.core.widget.doOnTextChanged +import androidx.fragment.app.viewModels +import com.gh.base.fragment.WaitingDialogFragment +import com.gh.common.util.* +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.FragmentManuallyRealNameBinding +import com.gh.gamecenter.entity.IdCardEntity +import com.gh.gamecenter.normal.NormalFragment +import com.squareup.picasso.Picasso +import io.reactivex.disposables.Disposable + +class ManuallyRealNameFragment : NormalFragment() { + + private var mDialog: WaitingDialogFragment? = null + private var mDisposable: Disposable? = null + + private val mViewModel: ManuallyRealNameViewModel by viewModels() + + private val mBinding: FragmentManuallyRealNameBinding by lazy { + FragmentManuallyRealNameBinding.inflate(layoutInflater) + } + + override fun getLayoutId(): Int = 0 + override fun getInflatedLayout(): View = mBinding.root + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + mBinding.toolbar.normalTitle.text = "人工审核" + mBinding.toolbar.normalToolbar.setNavigationOnClickListener { requireActivity().finish() } + + initView() + + mViewModel.resultLiveData.observe(viewLifecycleOwner) { + if (it) showSuccessView() + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + + if (data == null) return + if (requestCode == REQUEST_IMAGE) { + val selectedImage = data.data ?: return + val filePathColumn = arrayOf(MediaStore.Images.Media.DATA) + + val cursor = requireContext().contentResolver.query( + selectedImage, + filePathColumn, + null, + null, + null + ) ?: return + + cursor.moveToFirst() + + val columnIndex = cursor.getColumnIndex(filePathColumn[0]) + val picturePath = cursor.getString(columnIndex) + cursor.close() + + uploadPicture(selectedImage, picturePath) + } + } + + private fun initView() { + mBinding.imageIv.setOnClickListener { + PermissionHelper.checkStoragePermissionBeforeAction( + requireContext(), + object : EmptyCallback { + override fun onCallback() { + selectImage() + } + }) + } + + mBinding.clearIv.setOnClickListener { + removeUploadedImage() + updateSubmitBtn() + } + + mBinding.nameEt.setText(arguments?.getString(EntranceUtils.KEY_NAME) ?: "") + mBinding.idCardEt.setText(arguments?.getString(EntranceUtils.KEY_ID) ?: "") + + mBinding.nameEt.setSelection(mBinding.nameEt.text.length) + mBinding.idCardEt.setSelection(mBinding.idCardEt.text.length) + + mBinding.nameEt.doOnTextChanged { _, _, _, _ -> + updateSubmitBtn() + } + + mBinding.idCardEt.doOnTextChanged { _, _, _, _ -> + updateSubmitBtn() + } + + mBinding.clearIv.visibility = View.GONE + mBinding.contactTv.visibility = View.VISIBLE + mBinding.contactTv.enlargeTouchArea() + mBinding.contactTv.setOnClickListener { + DirectUtils.directToQqConversation(it.context, RealNameInfoFragment.CONTACT_QQ) + } + } + + private fun updateSubmitBtn() { + val validationPair = + isInputValid(mBinding.nameEt.text.toString(), mBinding.idCardEt.text.toString()) + + mBinding.submitBtn.isEnabled = validationPair.first + if (validationPair.first) { + mBinding.submitBtn.alpha = 1F + mBinding.submitBtn.setOnClickListener { + val idCardEntity = IdCardEntity( + id = mBinding.idCardEt.text.toString(), + name = mBinding.nameEt.text.toString(), + idPhoto = mViewModel.remoteImageUrl + ) + + mViewModel.postCertificationReview(idCardEntity) + } + } else { + mBinding.submitBtn.alpha = 0.4F + } + } + + private fun selectImage() { + val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) + startActivityForResult(intent, REQUEST_IMAGE) + } + + private fun removeUploadedImage() { + mViewModel.remoteImageUrl = null + mBinding.imageIv.setImageResource(R.drawable.bg_manually_real_name_image_placeholder) + } + + //上传图片 + private fun uploadPicture(internalImageUri: Uri, filePath: String) { + if (TextUtils.isEmpty(filePath)) return + + mDialog = WaitingDialogFragment.newInstance("上传图片中") + mDialog?.show(childFragmentManager, "loading") + + mDisposable = UploadImageUtils.uploadImage( + UploadImageUtils.UploadType.id_photo, + filePath, + object : UploadImageUtils.OnUploadImageListener { + override fun onSuccess(imageUrl: String) { + if (!isAdded) return + + mDialog?.dismissAllowingStateLoss() + mViewModel.remoteImageUrl = imageUrl + + mBinding.clearIv.visibility = View.VISIBLE + Picasso.with(requireContext()).load(internalImageUri).into(mBinding.imageIv) + updateSubmitBtn() + } + + override fun onError(e: Throwable?) { + mDialog?.dismissAllowingStateLoss() + ToastUtils.toast("图片上传失败 ${e?.localizedMessage}") + } + + override fun onProgress(total: Long, progress: Long) { + // do nothing + } + }) + } + + private fun showSuccessView() { + mBinding.successContainer.visibility = View.VISIBLE + } + + private fun isInputValid(name: String, idCard: String): Pair { + if (TextUtils.isEmpty(name)) { + return Pair(false, "请输入姓名") + } + + if (TextUtils.isEmpty(idCard)) { + return Pair(false, "请输入证件号码") + } + + if (mViewModel.remoteImageUrl == null) { + return Pair(false, "请上传证件照") + } + + return Pair(true, "") + } + + companion object { + const val REQUEST_IMAGE = 101 + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/halo/assistant/fragment/user/ManuallyRealNameViewModel.kt b/app/src/main/java/com/halo/assistant/fragment/user/ManuallyRealNameViewModel.kt new file mode 100644 index 0000000000..95937914e3 --- /dev/null +++ b/app/src/main/java/com/halo/assistant/fragment/user/ManuallyRealNameViewModel.kt @@ -0,0 +1,52 @@ +package com.halo.assistant.fragment.user + +import android.annotation.SuppressLint +import android.app.Application +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.MutableLiveData +import com.gh.common.util.ErrorHelper +import com.gh.common.util.GsonUtils +import com.gh.gamecenter.entity.IdCardEntity +import com.gh.gamecenter.entity.UserInfoEntity +import com.gh.gamecenter.retrofit.BiResponse +import com.gh.gamecenter.retrofit.RetrofitManager +import com.halo.assistant.HaloApp +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers +import okhttp3.MediaType +import okhttp3.RequestBody +import okhttp3.ResponseBody +import retrofit2.HttpException + +class ManuallyRealNameViewModel(application: Application) : AndroidViewModel(application) { + + var remoteImageUrl: String ?= null + + var resultLiveData = MutableLiveData() + + @SuppressLint("CheckResult") + fun postCertificationReview(idCardEntity: IdCardEntity) { + val userInfoEntity = UserInfoEntity() + userInfoEntity.idCard = idCardEntity + val body = RequestBody.create( + MediaType.parse("application/json"), GsonUtils.toJson(userInfoEntity) + ) + RetrofitManager.getInstance(HaloApp.getInstance()).api.postCertificationReview(body) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : BiResponse() { + override fun onFailure(exception: Exception) { + ErrorHelper.handleError( + HaloApp.getInstance(), + (exception as? HttpException)?.response()?.errorBody()?.string() + ) + } + + override fun onSuccess(data: ResponseBody?) { + resultLiveData.postValue(true) + } + }) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoFragment.kt b/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoFragment.kt index b000aca5e4..6a835081c7 100644 --- a/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoFragment.kt +++ b/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoFragment.kt @@ -11,14 +11,17 @@ import androidx.core.widget.doOnTextChanged import androidx.fragment.app.viewModels import com.gh.common.util.* import com.gh.common.view.CustomLinkMovementMethod +import com.gh.download.DownloadManager import com.gh.gamecenter.R import com.gh.gamecenter.ShellActivity import com.gh.gamecenter.databinding.FragmentRealNameBinding import com.gh.gamecenter.normal.NormalFragment +import kotlinx.android.synthetic.main.fragment_real_name.* import org.json.JSONObject class RealNameInfoFragment : NormalFragment() { + private var mHasBackdoor: Boolean = false // 是否留有不实名完成也自动开始下载的后门 private var mIsForcedToCertificate: Boolean = false private val mViewModel: RealNameInfoViewModel by viewModels() @@ -35,7 +38,10 @@ class RealNameInfoFragment : NormalFragment() { super.onViewCreated(view, savedInstanceState) mIsForcedToCertificate = - arguments?.getBoolean(EntranceUtils.KEY_IS_FORCED_TO_CERTICIFICE) ?: false + arguments?.getBoolean(EntranceUtils.KEY_IS_FORCED_TO_CERTIFICATE) ?: false + mHasBackdoor = + arguments?.getBoolean(EntranceUtils.KEY_IS_FORCED_TO_CERTIFICATE_BUT_WITH_BACKDOOR) + ?: false mBinding.toolbar.normalTitle.text = "实名认证" mBinding.toolbar.normalToolbar.setNavigationOnClickListener { requireActivity().finish() } @@ -54,6 +60,13 @@ class RealNameInfoFragment : NormalFragment() { } } + override fun onParentActivityFinish() { + super.onParentActivityFinish() + if (mHasBackdoor) { + DownloadManager.getInstance(requireContext()).resumeAllInvisiblePendingTask() + } + } + private fun isRealNameInfoExist(): Boolean { val userInfoEntity = mViewModel.getUserInfo() return if (userInfoEntity != null) { @@ -95,7 +108,30 @@ class RealNameInfoFragment : NormalFragment() { .bold(0, 5) .build() - mBinding.nameEt.filters = arrayOf(TextHelper.getFilter(20, "最多20个字")) + val manualHintString = "若您提交的真实身份信息未通过认证或者您持有的为港澳台\\国外身份证件,可转交人工审核" + mBinding.manualHintTv.text = + SpanBuilder(manualHintString) + .click( + manualHintString.length - "人工审核".length, + manualHintString.length, + isUnderlineText = true, + colorRes = R.color.theme_font + ) { + startActivity( + ShellActivity.getIntent( + requireContext(), + ShellActivity.Type.MANUALLY_REAL_NAME, + Bundle().apply { + putString(EntranceUtils.KEY_NAME, nameEt.text.toString()) + putString(EntranceUtils.KEY_ID, idCardEt.text.toString()) + } + ) + ) + requireActivity().finish() + } + .build() + mBinding.manualHintTv.movementMethod = CustomLinkMovementMethod.getInstance() + mBinding.idCardEt.filters = arrayOf(TextHelper.getFilter(18, "身份证号码最长18位")) mBinding.nameEt.doOnTextChanged { _, _, _, _ -> @@ -104,6 +140,16 @@ class RealNameInfoFragment : NormalFragment() { mBinding.idCardEt.doOnTextChanged { _, _, _, _ -> updateSubmitBtn() } + mBinding.contactTv.visibility = View.VISIBLE + mBinding.contactTv.enlargeTouchArea() + mBinding.contactTv.setOnClickListener { + DirectUtils.directToQqConversation(it.context, CONTACT_QQ) + } + + // 适配小屏幕 or 大文字手机 + if (isScreenUnableToShowAllTheContent()) { + changeToCompatView() + } } private fun initDisplayOnlyView() { @@ -111,8 +157,7 @@ class RealNameInfoFragment : NormalFragment() { mBinding.badgeContainer.visibility = View.VISIBLE mBinding.run { - val set = ConstraintSet() - set.run { + ConstraintSet().run { clone(infoContainer) clear(R.id.nameTv, ConstraintSet.TOP) connect( @@ -146,7 +191,7 @@ class RealNameInfoFragment : NormalFragment() { mBinding.reEditInfoBtn.setOnClickListener { startActivity( ShellActivity.getIntent(requireContext(), ShellActivity.Type.REAL_NAME_INFO).apply { - putExtra(EntranceUtils.KEY_IS_FORCED_TO_CERTICIFICE, true) + putExtra(EntranceUtils.KEY_IS_FORCED_TO_CERTIFICATE, true) } ) requireActivity().finish() @@ -159,7 +204,7 @@ class RealNameInfoFragment : NormalFragment() { mBinding.submitBtn.isEnabled = validationPair.first if (validationPair.first) { - mBinding.submitBtn.background = R.drawable.button_round_2496ff.toDrawable() + mBinding.submitBtn.alpha = 1F mBinding.submitBtn.setOnClickListener { val o = JSONObject() o.put("id", mBinding.idCardEt.text.toString()) @@ -167,7 +212,7 @@ class RealNameInfoFragment : NormalFragment() { mViewModel.postCertification(o.toString(), mIsForcedToCertificate) } } else { - mBinding.submitBtn.background = R.drawable.button_round_2496ff_alpha_40.toDrawable() + mBinding.submitBtn.alpha = 0.4F } mBinding.errorHintTv.text = validationPair.second } @@ -191,4 +236,95 @@ class RealNameInfoFragment : NormalFragment() { return Pair(true, "") } + /** + * 屏幕高度小于等于 1080 (16:9) 的设备看作无法显示完整内容 + */ + private fun isScreenUnableToShowAllTheContent(): Boolean { + return DisplayUtils.getScreenHeight() <= 1080 + } + + private fun changeToCompatView() { + mBinding.bodyTv.setLineSpacing(0F, 1F) + mBinding.hintTv.setLineSpacing(0F, 1F) + mBinding.manualHintTv.setLineSpacing(0F, 1F) + + // 把空隙缩窄 + ConstraintSet().apply { + clone(mBinding.infoContainer) + clear(R.id.nameTv, ConstraintSet.TOP) + connect( + R.id.nameTv, + ConstraintSet.TOP, + R.id.hintTv, + ConstraintSet.BOTTOM, + 4F.dip2px() + ) + }.applyTo(mBinding.infoContainer) + + ConstraintSet().apply { + clone(mBinding.infoContainer) + clear(R.id.idCardTv, ConstraintSet.TOP) + connect( + R.id.idCardTv, + ConstraintSet.TOP, + R.id.nameEt, + ConstraintSet.BOTTOM, + 4F.dip2px() + ) + }.applyTo(mBinding.infoContainer) + + ConstraintSet().apply { + clone(mBinding.infoContainer) + clear(R.id.nameEt, ConstraintSet.TOP) + connect( + R.id.nameEt, + ConstraintSet.TOP, + R.id.nameTv, + ConstraintSet.BOTTOM, + 4F.dip2px() + ) + }.applyTo(mBinding.infoContainer) + + ConstraintSet().apply { + clone(mBinding.infoContainer) + clear(R.id.idCardEt, ConstraintSet.TOP) + connect( + R.id.idCardEt, + ConstraintSet.TOP, + R.id.idCardTv, + ConstraintSet.BOTTOM, + 4F.dip2px() + ) + }.applyTo(mBinding.infoContainer) + + ConstraintSet().apply { + clone(mBinding.infoContainer) + clear(R.id.hintTv, ConstraintSet.TOP) + connect( + R.id.hintTv, + ConstraintSet.TOP, + R.id.bodyTv, + ConstraintSet.BOTTOM, + 4F.dip2px() + ) + }.applyTo(mBinding.infoContainer) + + // 把按钮上移 + ConstraintSet().apply { + clone(mBinding.infoContainer) + clear(R.id.submitBtn, ConstraintSet.TOP) + connect( + R.id.submitBtn, + ConstraintSet.TOP, + R.id.idCardEt, + ConstraintSet.BOTTOM, + 4F.dip2px() + ) + }.applyTo(mBinding.infoContainer) + } + + companion object { + const val CONTACT_QQ = "800177318" + } + } \ No newline at end of file diff --git a/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoViewModel.kt b/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoViewModel.kt index 02098f9ddc..fad49ae878 100644 --- a/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoViewModel.kt +++ b/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoViewModel.kt @@ -114,7 +114,6 @@ class RealNameInfoViewModel(application: Application) : AndroidViewModel(applica PackageInstaller.install(HaloApp.getInstance(), pendingDownloadEntity) RealNameHelper.pendingInstallPkgPath = "" } - } } \ No newline at end of file diff --git a/app/src/main/java/com/halo/assistant/fragment/user/UserInfoEditFragment.java b/app/src/main/java/com/halo/assistant/fragment/user/UserInfoEditFragment.java index 05ea19422b..284c251c7c 100644 --- a/app/src/main/java/com/halo/assistant/fragment/user/UserInfoEditFragment.java +++ b/app/src/main/java/com/halo/assistant/fragment/user/UserInfoEditFragment.java @@ -127,7 +127,7 @@ public class UserInfoEditFragment extends NormalFragment { super.onCreate(savedInstanceState); setHasOptionsMenu(true); mEditType = getArguments().getString(UserViewModel.KEY_EDIT_TYPE); - mIsForcedToCertificate = getArguments().getBoolean(EntranceUtils.KEY_IS_FORCED_TO_CERTICIFICE); + mIsForcedToCertificate = getArguments().getBoolean(EntranceUtils.KEY_IS_FORCED_TO_CERTIFICATE); initMenu(R.menu.menu_button); mSaveMenuItem = getItemMenu(R.id.menu_button); diff --git a/app/src/main/res/drawable-xxxhdpi/bg_manually_real_name_image_placeholder.webp b/app/src/main/res/drawable-xxxhdpi/bg_manually_real_name_image_placeholder.webp new file mode 100644 index 0000000000..bd31a4bf2c Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_manually_real_name_image_placeholder.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_manually_real_name_success.webp b/app/src/main/res/drawable-xxxhdpi/ic_manually_real_name_success.webp new file mode 100644 index 0000000000..4eb9a447af Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_manually_real_name_success.webp differ diff --git a/app/src/main/res/layout/fragment_manually_real_name.xml b/app/src/main/res/layout/fragment_manually_real_name.xml new file mode 100644 index 0000000000..af0cebe6e9 --- /dev/null +++ b/app/src/main/res/layout/fragment_manually_real_name.xml @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_real_name.xml b/app/src/main/res/layout/fragment_real_name.xml index 242972ca73..da9911cfb4 100644 --- a/app/src/main/res/layout/fragment_real_name.xml +++ b/app/src/main/res/layout/fragment_real_name.xml @@ -140,7 +140,8 @@ android:layout_width="match_parent" android:layout_height="44dp" android:layout_marginTop="100dp" - android:background="@drawable/button_round_2496ff_alpha_40" + android:alpha="0.4" + android:background="@drawable/download_button_normal_style" android:gravity="center" android:text="提交" android:textColor="@color/white" @@ -150,6 +151,20 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/idCardEt" /> + + + + \ No newline at end of file diff --git a/dependencies.gradle b/dependencies.gradle index a5b3ff335a..1c8902ba2b 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -105,6 +105,7 @@ ext { toolargetool = "0.3.0" chart = "3.1.0" zip4j = "2.6.1" + easyProtector = "1.1.2" whatTheStack = "0.1.0_rt" apkParser = "v2.6.10" nanohttpd = "2.3.1" diff --git a/gradle.properties b/gradle.properties index 6d26798563..b8bc5b1866 100644 --- a/gradle.properties +++ b/gradle.properties @@ -52,7 +52,7 @@ QUICK_LOGIN_APPKEY=002BAABA2C078342DA33BEAB0A4C6A25 # hosts DEV_API_HOST=https\://dev-and-api.ghzs.com/v5d5d0/ -API_HOST=https\://and-api.ghzs.com/v5d4d0/ +API_HOST=https\://and-api.ghzs.com/v5d5d0/ android.useAndroidX=true android.enableJetifier=true diff --git a/scripts/jenkins_flutter_build.sh b/scripts/jenkins_flutter_build.sh index 2cd7c74eec..9577b6a7d1 100755 --- a/scripts/jenkins_flutter_build.sh +++ b/scripts/jenkins_flutter_build.sh @@ -35,12 +35,9 @@ if [ ! -f app/build/outputs/apk/internal/release/app-internal-release.apk ]; the fi mv app/build/outputs/apk/internal/release/app-internal-release.apk app/build/tmp/${version}-${versionCode}-internal-${build_time}.apk -./gradlew rPR -I init.flutter.gradle -if [ ! -f app/build/outputs/apk/publish/release/app-publish-release.apk ]; then - ./gradlew rPR -I init.gradle -fi -mv app/build/outputs/apk/publish/release/app-publish-release.apk app/build/tmp/${version}-${versionCode}-publish-${build_time}.apk - git checkout app/build.gradle git checkout gradle.properties -git checkout settings.gradle \ No newline at end of file +git checkout settings.gradle + +cd assistant_flutter +git checkout pubspec.lock \ No newline at end of file