zouyong 5 years ago
commit
ca7989681d
94 changed files with 3866 additions and 0 deletions
  1. 16 0
      .gitignore
  2. 3 0
      .idea/.gitignore
  3. 1 0
      .idea/.name
  4. 6 0
      .idea/compiler.xml
  5. 20 0
      .idea/gradle.xml
  6. 35 0
      .idea/jarRepositories.xml
  7. 9 0
      .idea/misc.xml
  8. 10 0
      .idea/runConfigurations.xml
  9. 6 0
      .idea/vcs.xml
  10. 3 0
      README.md
  11. 1 0
      app/.gitignore
  12. 88 0
      app/build.gradle
  13. 17 0
      app/gradle.properties
  14. BIN
      app/keystore/jjdzkey.jks
  15. BIN
      app/libs/GDTSDK.unionNormal.4.351.1221.aar
  16. BIN
      app/libs/anythink_banner.aar
  17. BIN
      app/libs/anythink_china_core.aar
  18. BIN
      app/libs/anythink_core.aar
  19. BIN
      app/libs/anythink_interstitial.aar
  20. BIN
      app/libs/anythink_native.aar
  21. BIN
      app/libs/anythink_network_gdt.aar
  22. BIN
      app/libs/anythink_network_kuaishou.aar
  23. BIN
      app/libs/anythink_network_pangle_china.aar
  24. BIN
      app/libs/anythink_network_sigmob.aar
  25. BIN
      app/libs/anythink_rewardvideo.aar
  26. BIN
      app/libs/anythink_splash.aar
  27. BIN
      app/libs/dy-task-sdk-2.0.7.aar
  28. BIN
      app/libs/gson-2.8.4.jar
  29. BIN
      app/libs/kssdk-ad--3.3.9-publishRelease-4ea04e00c.aar
  30. BIN
      app/libs/oaid_sdk_1.0.25.aar
  31. BIN
      app/libs/open_ad_sdk_3.6.1.0.aar
  32. BIN
      app/libs/tramini_sdk.aar
  33. BIN
      app/libs/umeng-abtest-v1.0.0.aar
  34. BIN
      app/libs/umeng-asms-armeabi-v1.2.2.aar
  35. BIN
      app/libs/umeng-common-9.3.8.jar
  36. BIN
      app/libs/windAd-3.0.1.aar
  37. 21 0
      app/proguard-rules.pro
  38. 115 0
      app/src/main/AndroidManifest.xml
  39. 187 0
      app/src/main/java/com/aries/jjdz/mz/JavaScriptInterface.java
  40. 99 0
      app/src/main/java/com/aries/jjdz/mz/MainActivity.java
  41. 84 0
      app/src/main/java/com/aries/jjdz/mz/wxapi/WXEntryActivity.java
  42. 58 0
      app/src/main/java/com/mokasz/ad/ADReport.java
  43. 104 0
      app/src/main/java/com/mokasz/ad/BannerAD.java
  44. 19 0
      app/src/main/java/com/mokasz/ad/Constants.java
  45. 67 0
      app/src/main/java/com/mokasz/ad/InterstitialAD.java
  46. 144 0
      app/src/main/java/com/mokasz/ad/NativeExpressAD.java
  47. 213 0
      app/src/main/java/com/mokasz/ad/NativeRender.java
  48. 75 0
      app/src/main/java/com/mokasz/ad/RewardVideoAD.java
  49. 72 0
      app/src/main/java/com/mokasz/ad/SplashADActivity.java
  50. 109 0
      app/src/main/java/com/mokasz/libs/DownLoadHandler.java
  51. 194 0
      app/src/main/java/com/mokasz/libs/MOKActivity.java
  52. 229 0
      app/src/main/java/com/mokasz/libs/SoftKeyboardFixerForFullscreen.java
  53. 7 0
      app/src/main/java/com/mokasz/libs/ZipExtractorListener.java
  54. 177 0
      app/src/main/java/com/mokasz/libs/ZipExtractorTask.java
  55. 305 0
      app/src/main/java/com/mokasz/libs/utils/FileUtil.java
  56. 49 0
      app/src/main/java/com/mokasz/libs/utils/GameUtil.java
  57. 103 0
      app/src/main/java/com/mokasz/libs/utils/GeneralUtil.java
  58. 81 0
      app/src/main/java/com/mokasz/libs/utils/OaidHelper.java
  59. 121 0
      app/src/main/java/com/mokasz/libs/utils/OkhttpUtil.java
  60. 206 0
      app/src/main/java/com/mokasz/libs/utils/SystemUtil.java
  61. 19 0
      app/src/main/java/com/mokasz/libs/utils/ToastUtil.java
  62. 91 0
      app/src/main/java/com/mokasz/libs/utils/WechatUtil.java
  63. 22 0
      app/src/main/java/com/mokasz/receiver/InstallReceiver.java
  64. 29 0
      app/src/main/java/com/mokasz/utils/BroadcastUtil.java
  65. BIN
      app/src/main/res/drawable/ad_close.png
  66. BIN
      app/src/main/res/drawable/ad_logo.png
  67. BIN
      app/src/main/res/drawable/chapin.png
  68. BIN
      app/src/main/res/drawable/logo.png
  69. BIN
      app/src/main/res/drawable/ren.png
  70. BIN
      app/src/main/res/drawable/share_icon.png
  71. BIN
      app/src/main/res/drawable/splash.jpg
  72. 80 0
      app/src/main/res/layout/activity_main.xml
  73. 13 0
      app/src/main/res/layout/banner_ad.xml
  74. 17 0
      app/src/main/res/layout/native_ad.xml
  75. 142 0
      app/src/main/res/layout/native_ad_item.xml
  76. 15 0
      app/src/main/res/layout/splash.xml
  77. 20 0
      app/src/main/res/layout/splash_ad.xml
  78. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher.png
  79. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher.png
  80. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher.png
  81. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  82. 10 0
      app/src/main/res/values/colors.xml
  83. 3 0
      app/src/main/res/values/strings.xml
  84. 9 0
      app/src/main/res/values/style.xml
  85. 17 0
      app/src/main/res/xml/anythink_bk_gdt_file_path.xml
  86. 14 0
      app/src/main/res/xml/anythink_bk_sigmob_file_path.xml
  87. 16 0
      app/src/main/res/xml/anythink_bk_tt_file_path.xml
  88. 4 0
      app/src/main/res/xml/file_path.xml
  89. 27 0
      build.gradle
  90. BIN
      gradle/wrapper/gradle-wrapper.jar
  91. 6 0
      gradle/wrapper/gradle-wrapper.properties
  92. 172 0
      gradlew
  93. 84 0
      gradlew.bat
  94. 2 0
      settings.gradle

+ 16 - 0
.gitignore

@@ -0,0 +1,16 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
+app/release/

+ 3 - 0
.idea/.gitignore

@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml

+ 1 - 0
.idea/.name

@@ -0,0 +1 @@
+TD_JJ

+ 6 - 0
.idea/compiler.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <bytecodeTargetLevel target="11" />
+  </component>
+</project>

+ 20 - 0
.idea/gradle.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="GradleMigrationSettings" migrationVersion="1" />
+  <component name="GradleSettings">
+    <option name="linkedExternalProjectsSettings">
+      <GradleProjectSettings>
+        <option name="testRunner" value="PLATFORM" />
+        <option name="distributionType" value="DEFAULT_WRAPPED" />
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
+        <option name="modules">
+          <set>
+            <option value="$PROJECT_DIR$" />
+            <option value="$PROJECT_DIR$/app" />
+          </set>
+        </option>
+        <option name="resolveModulePerSourceSet" value="false" />
+      </GradleProjectSettings>
+    </option>
+  </component>
+</project>

+ 35 - 0
.idea/jarRepositories.xml

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RemoteRepositoriesConfiguration">
+    <remote-repository>
+      <option name="id" value="central" />
+      <option name="name" value="Maven Central repository" />
+      <option name="url" value="https://repo1.maven.org/maven2" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="jboss.community" />
+      <option name="name" value="JBoss Community repository" />
+      <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="MavenRepo" />
+      <option name="name" value="MavenRepo" />
+      <option name="url" value="https://repo.maven.apache.org/maven2/" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="BintrayJCenter" />
+      <option name="name" value="BintrayJCenter" />
+      <option name="url" value="https://jcenter.bintray.com/" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="Google" />
+      <option name="name" value="Google" />
+      <option name="url" value="https://dl.google.com/dl/android/maven2/" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="maven" />
+      <option name="name" value="maven" />
+      <option name="url" value="https://jitpack.io" />
+    </remote-repository>
+  </component>
+</project>

+ 9 - 0
.idea/misc.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/build/classes" />
+  </component>
+  <component name="ProjectType">
+    <option name="id" value="Android" />
+  </component>
+</project>

+ 10 - 0
.idea/runConfigurations.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RunConfigurationProducerService">
+    <option name="ignoredProducers">
+      <set>
+        <option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
+      </set>
+    </option>
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 3 - 0
README.md

@@ -0,0 +1,3 @@
+# MOKA-TD-JJ-AndroidMini
+
+微端工程

+ 1 - 0
app/.gitignore

@@ -0,0 +1 @@
+/build

+ 88 - 0
app/build.gradle

@@ -0,0 +1,88 @@
+plugins {
+    id 'com.android.application'
+}
+
+android {
+    compileSdkVersion 28
+    buildToolsVersion '29.0.2'
+
+    defaultConfig {
+        applicationId "com.aries.jjdz.mz"
+        minSdkVersion 21
+        //noinspection ExpiredTargetSdkVersion
+        targetSdkVersion 28
+        versionCode "${VERSION_CODE}".toInteger()
+        versionName "${VERSION_NAME}"
+        multiDexEnabled true
+    }
+    signingConfigs {
+        release {
+            storeFile file('./keystore/jjdzkey.jks')
+            storePassword "szmoka"
+            keyAlias "jjdzkey"
+            keyPassword "szmoka"
+        }
+    }
+    buildTypes {
+        release {
+            signingConfig signingConfigs.release
+            /**
+             * 配置BuildConfig自动获取字段
+             */
+            buildConfigField "String", "TF_CHANNEL", "${TF_CHANNEL}"
+            buildConfigField "String", "JL_AID", "${JL_AID}"
+            buildConfigField "String", "JL_CHANNEL", "${JL_CHANNEL}"
+            buildConfigField "String", "KS_AID", "${KS_AID}"
+            buildConfigField "String", "KS_ANAME", "${KS_ANAME}"
+            buildConfigField "String", "KS_CHANNEL", "${KS_CHANNEL}"
+            buildConfigField "String", "UM_AID", "${UM_AID}"
+            buildConfigField "String", "UM_CHANNEL", "${UM_CHANNEL}"
+            buildConfigField "String", "UM_SECRET", "${UM_SECRET}"
+            buildConfigField "String", "WX_APP_ID", "${WX_APP_ID}"
+            buildConfigField "String", "TOPON", "${TOPON}"
+        }
+
+        debug {
+            signingConfig signingConfigs.release
+            /**
+             * 配置BuildConfig自动获取字段
+             */
+            buildConfigField "String", "TF_CHANNEL", "${TF_CHANNEL}"
+            buildConfigField "String", "JL_AID", "${JL_AID}"
+            buildConfigField "String", "JL_CHANNEL", "${JL_CHANNEL}"
+            buildConfigField "String", "KS_AID", "${KS_AID}"
+            buildConfigField "String", "KS_ANAME", "${KS_ANAME}"
+            buildConfigField "String", "KS_CHANNEL", "${KS_CHANNEL}"
+            buildConfigField "String", "UM_AID", "${UM_AID}"
+            buildConfigField "String", "UM_CHANNEL", "${UM_CHANNEL}"
+            buildConfigField "String", "UM_SECRET", "${UM_SECRET}"
+            buildConfigField "String", "WX_APP_ID", "${WX_APP_ID}"
+            buildConfigField "String", "TOPON", "${TOPON}"
+        }
+    }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+}
+
+dependencies {
+    implementation fileTree(dir: '../libs', include: ['*.jar', '*.aar'])
+    implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
+
+    implementation 'com.github.smarxpan:NotchScreenTool:0.0.1'
+    implementation 'com.liulishuo.filedownloader:library:1.7.7'
+    implementation "com.squareup.okhttp3:okhttp:4.8.0"
+    implementation 'ren.yale.android:cachewebviewlib:2.2.1'
+
+    //广告SDK
+    implementation "com.android.support:design:28.0.0"
+    implementation 'com.android.support:multidex:1.0.3'
+    implementation "com.android.support:support-v4:28.0.0"
+    implementation "com.android.support:appcompat-v7:28.0.0"
+    implementation "com.android.support:recyclerview-v7:28.0.0"
+    implementation "com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.7.4"
+    implementation "com.github.bumptech.glide:glide:4.8.0"
+    implementation 'com.android.support.constraint:constraint-layout:2.0.1'
+    annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
+}

+ 17 - 0
app/gradle.properties

@@ -0,0 +1,17 @@
+TF_CHANNEL="1"
+UM_AID="607ea8095844f15425dff5c6"
+UM_CHANNEL="juliang_kaixinnongleyuan"
+MY_APP_NAME=\u5f00\u5fc3\u519c\u4e50\u56ed
+WX_APP_ID="wxd90e9f448c4d179e"
+UM_SECRET="432e41656d8208c94c9a59c134a0b2cb"
+KS_ANAME=""
+VERSION_CODE=1
+#id,key,reward,interstitial,native,splash,banner,fullscreen
+TOPON="a60cd99bf8b3fb,66b742dd0e502b64d783d9c66a9d30c4,b60cd9a516fcd4,b60cd9a51bf017,b60cd9a52f3b29,b60cd9a526e104,b60cd9a52b931a,b60cd9a5207fd8"
+VERSION_NAME=1.0.0
+APP_CONFIG_CODE=""
+JL_CHANNEL="juliang"
+KS_CHANNEL=""
+PACKAGE_NAME=com.aries.jjdz.mz
+KS_AID=""
+JL_AID="215656"

BIN
app/keystore/jjdzkey.jks


BIN
app/libs/GDTSDK.unionNormal.4.351.1221.aar


BIN
app/libs/anythink_banner.aar


BIN
app/libs/anythink_china_core.aar


BIN
app/libs/anythink_core.aar


BIN
app/libs/anythink_interstitial.aar


BIN
app/libs/anythink_native.aar


BIN
app/libs/anythink_network_gdt.aar


BIN
app/libs/anythink_network_kuaishou.aar


BIN
app/libs/anythink_network_pangle_china.aar


BIN
app/libs/anythink_network_sigmob.aar


BIN
app/libs/anythink_rewardvideo.aar


BIN
app/libs/anythink_splash.aar


BIN
app/libs/dy-task-sdk-2.0.7.aar


BIN
app/libs/gson-2.8.4.jar


BIN
app/libs/kssdk-ad--3.3.9-publishRelease-4ea04e00c.aar


BIN
app/libs/oaid_sdk_1.0.25.aar


BIN
app/libs/open_ad_sdk_3.6.1.0.aar


BIN
app/libs/tramini_sdk.aar


BIN
app/libs/umeng-abtest-v1.0.0.aar


BIN
app/libs/umeng-asms-armeabi-v1.2.2.aar


BIN
app/libs/umeng-common-9.3.8.jar


BIN
app/libs/windAd-3.0.1.aar


+ 21 - 0
app/proguard-rules.pro

@@ -0,0 +1,21 @@
+# 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

+ 115 - 0
app/src/main/AndroidManifest.xml

@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.aries.jjdz.mz">
+
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.GET_TASKS" />
+    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:resizeableActivity="false"
+        android:supportsRtl="true"
+        android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+        android:hardwareAccelerated="true"
+        android:usesCleartextTraffic="true">
+        <activity
+            android:name=".MainActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize"
+            android:launchMode="singleTask"
+            android:screenOrientation="portrait"
+            android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+            android:windowSoftInputMode="adjustPan|stateAlwaysVisible">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <!-- 以下是广告 -->
+        <activity
+            android:name="com.mokasz.ad.SplashADActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize|screenLayout"
+            android:fitsSystemWindows="true"
+            android:label="@string/app_name"
+            android:launchMode="singleTop"
+            android:screenOrientation="portrait"
+            android:taskAffinity="com.aries.jjdz.mz"
+            android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
+            <!--            <intent-filter>-->
+            <!--                <action android:name="android.intent.action.MAIN" />-->
+            <!--                <category android:name="android.intent.category.LAUNCHER" />-->
+            <!--            </intent-filter>-->
+        </activity>
+
+        <!--        微信回跳-->
+        <activity
+            android:name=".wxapi.WXEntryActivity"
+            android:configChanges="orientation|keyboardHidden|screenSize|screenLayout"
+            android:exported="true"
+            android:fitsSystemWindows="true"
+            android:label="@string/app_name"
+            android:launchMode="singleTop"
+            android:screenOrientation="portrait"
+            android:taskAffinity="com.aries.jjdz.mz"
+            android:theme="@style/wxTheme" />
+
+        <provider
+            android:name="android.support.v4.content.FileProvider"
+            android:authorities="${applicationId}.fileprovider"
+            android:exported="false"
+            android:grantUriPermissions="true">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/file_path" />
+        </provider>
+
+
+        <uses-library
+            android:name="org.apache.http.legacy"
+            android:required="false" />
+        <!-- source file: china/network_sdk/pangle/AndroidManifest.xml -->
+        <provider
+            android:name="com.bytedance.sdk.openadsdk.multipro.TTMultiProvider"
+            android:authorities="${applicationId}.TTMultiProvider"
+            android:exported="false" />
+        <provider
+            android:name="com.bytedance.sdk.openadsdk.TTFileProvider"
+            android:authorities="${applicationId}.TTFileProvider"
+            android:exported="false"
+            android:grantUriPermissions="true">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/anythink_bk_tt_file_path" />
+        </provider>
+        <!-- source file: china/network_sdk/gdt/AndroidManifest.xml -->
+
+        <provider
+            android:name="com.qq.e.comm.GDTFileProvider"
+            android:authorities="${applicationId}.gdt.fileprovider"
+            android:exported="false"
+            android:grantUriPermissions="true">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/anythink_bk_gdt_file_path" />
+        </provider>
+
+        <provider
+            android:name="com.sigmob.sdk.SigmobFileProvider"
+            android:authorities="${applicationId}.sigprovider"
+            android:exported="false"
+            android:grantUriPermissions="true">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/anythink_bk_sigmob_file_path" />
+        </provider>
+    </application>
+
+</manifest>

+ 187 - 0
app/src/main/java/com/aries/jjdz/mz/JavaScriptInterface.java

@@ -0,0 +1,187 @@
+package com.aries.jjdz.mz;
+
+import android.Manifest;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.util.Log;
+import android.webkit.JavascriptInterface;
+
+import com.mokasz.ad.BannerAD;
+import com.mokasz.ad.InterstitialAD;
+import com.mokasz.ad.RewardVideoAD;
+import com.mokasz.libs.MOKActivity;
+import com.mokasz.libs.utils.GameUtil;
+import com.mokasz.libs.utils.GeneralUtil;
+import com.mokasz.libs.utils.OkhttpUtil;
+import com.mokasz.libs.utils.SystemUtil;
+import com.mokasz.libs.utils.WechatUtil;
+import com.smarx.notchlib.NotchScreenManager;
+import com.smarx.notchlib.utils.ScreenUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class JavaScriptInterface {
+    private MainActivity activity;
+    private static InterstitialAD interstitialAD;
+    private static InterstitialAD fullScreenAD;
+    private static RewardVideoAD rewardVideoAD;
+    private BannerAD bannerAD;
+
+    JavaScriptInterface(MainActivity activity) {
+        this.activity = activity;
+//        interstitialAD = new InterstitialAD(activity,false);
+//        fullScreenAD = new InterstitialAD(activity,true);
+//        rewardVideoAD = new RewardVideoAD(activity);
+//        bannerAD = new BannerAD(this.activity);
+    }
+
+    @JavascriptInterface
+    public void restart() {
+        ((MainActivity) activity).restart();
+    }
+
+    @JavascriptInterface
+    public String checkGameVersion(String version) {
+        return GameUtil.checkGameVersion(activity, version);
+    }
+
+    @JavascriptInterface
+    public void openBrower(String url) {
+        Uri uri = Uri.parse(url);
+        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+        activity.startActivity(intent);
+    }
+
+    @JavascriptInterface
+    public void appInit() {
+        checkPermissions();
+        activity.showWebview();
+        //刘海屏高度设置
+        NotchScreenManager.getInstance().getNotchInfo(activity, notchScreenInfo -> {
+            Log.i("MokaGame", "Is this screen notch? " + notchScreenInfo.hasNotch);
+            if (notchScreenInfo.hasNotch) {
+                for (Rect rect : notchScreenInfo.notchRects) {
+                    Log.i("MokaGame", "notch screen Rect = " + rect.toShortString());
+                    activity.webView.post(() -> {
+                        float screenHeight = ScreenUtil.getScreenSize(activity)[1];
+                        float notchRatio = rect.bottom / screenHeight;
+                        activity.webView.evaluateJavascript("mobileBridge.notchRatio = " + notchRatio, null);
+                    });
+                }
+            }
+        });
+    }
+
+    @JavascriptInterface
+    public void checkPermissions() {
+        List<String> listPermissions = new ArrayList<>();
+        listPermissions.add(Manifest.permission.READ_PHONE_STATE);
+        listPermissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
+        if (SystemUtil.hasPermission(activity, listPermissions).isEmpty()) {
+            //拥有全部权限
+            String code = "g.deviceData.version='" + GeneralUtil.getVersionName(activity) + "';" +
+                    "g.deviceData.channel='" + BuildConfig.TF_CHANNEL + "';" +
+                    "g.deviceData.imei='" + SystemUtil.getIMEI(activity) + "';" +
+                    "g.deviceData.oaid='" + activity.OAID + "';" +
+                    "g.deviceData.androId='" + SystemUtil.getAndroidID(activity) + "';" +
+                    "g.deviceData.mac='" + SystemUtil.getMac(activity) + "';";
+            activity.webView.post(() -> activity.webView.evaluateJavascript(code, null));
+        } else {
+            SystemUtil.requestPermission(activity, listPermissions, 100);
+        }
+    }
+
+    @JavascriptInterface
+    public void downloadAndInstallByAPK(String url) {
+        OkhttpUtil.getInstance().download(((MOKActivity) activity), url, "apk", "");
+    }
+
+    @JavascriptInterface
+    public void downloadAndInstallByZIP(final String version, String remoteZIP) {
+        OkhttpUtil.getInstance().download(((MOKActivity) activity), remoteZIP, "zip", version);
+    }
+
+    /**
+     * 微信登录
+     */
+    @JavascriptInterface
+    public void wxLogin() {
+        WechatUtil.wxLogin(activity);
+    }
+
+    /**
+     * 微信登录
+     */
+    @JavascriptInterface
+    public void wxShare(String url, String title, String descroption) {
+        WechatUtil.shareLinkToWX(0, activity, url, title, descroption);
+    }
+
+    /**
+     * 显示全屏广告
+     */
+    @JavascriptInterface
+    public void showFullScreenAD() {
+        activity.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                fullScreenAD.showAD();
+            }
+        });
+    }
+
+    /**
+     * 显示插屏广告
+     */
+    @JavascriptInterface
+    public void showInterstitialAD() {
+        activity.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                interstitialAD.showAD();
+            }
+        });
+    }
+
+    /**
+     * 显示激励视频广告
+     */
+    @JavascriptInterface
+    public void showRewardVideoAD() {
+        activity.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                rewardVideoAD.showRewardVideoAD();
+            }
+        });
+    }
+
+    /**
+     * 初始化横屏广告
+     */
+    @JavascriptInterface
+    public void showBannerAD() {
+        activity.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if(bannerAD == null){
+                    bannerAD = new BannerAD(activity);
+                    bannerAD.show();
+                }
+            }
+        });
+    }
+
+    @JavascriptInterface
+    public void removeBannerAD() {
+        activity.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                bannerAD.hide();
+                bannerAD.load();
+            }
+        });
+    }
+}

+ 99 - 0
app/src/main/java/com/aries/jjdz/mz/MainActivity.java

@@ -0,0 +1,99 @@
+package com.aries.jjdz.mz;
+
+import android.annotation.SuppressLint;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+
+import com.anythink.core.api.ATSDK;
+import com.bun.miitmdid.core.MdidSdkHelper;
+import com.mokasz.ad.Constants;
+import com.mokasz.libs.MOKActivity;
+import com.mokasz.libs.utils.GeneralUtil;
+import com.mokasz.libs.utils.OaidHelper;
+import com.mokasz.libs.utils.SystemUtil;
+import com.mokasz.libs.utils.WechatUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class MainActivity extends MOKActivity {
+    private List<String> listPermissions;//应用权限列表
+    public String OAID;
+    @SuppressLint("JavascriptInterface")
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        //创建webview
+        createWebView("http://cp.mokasz.com:3000/tdjj/index.html?t=" + System.currentTimeMillis());
+//        createWebView("http://172.16.13.74:7456/");
+        //设置JS交互
+        webView.addJavascriptInterface(new JavaScriptInterface(this), "mobileBridge");
+
+        MdidSdkHelper.InitSdk(this, true, new OaidHelper(ids -> OAID = ids));//初始化获取OAID
+
+
+        WechatUtil.regToWX(this);
+
+        ATSDK.setNetworkLogDebug(true);//需要关闭
+        ATSDK.integrationChecking(getApplicationContext());
+        Log.e("MainActivity", "TOPON SDK版本:" + ATSDK.getSDKVersionName());//SDK版本
+        ATSDK.init(getApplicationContext(), Constants.APP_ID, Constants.APP_KEY);
+    }
+
+    /**
+     * 当游戏创建完成
+     */
+    protected void onGameCreated() {
+        super.onGameCreated();
+        //初始化权限列表
+        listPermissions = new ArrayList<>();
+        listPermissions.add(android.Manifest.permission.READ_PHONE_STATE);
+        listPermissions.add(android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        SystemUtil.hideBottomUIMenu(this);
+    }
+
+    /**
+     * 申请权限返回
+     *
+     * @param requestCode  传入的请求代码
+     * @param permissions  请求的权限
+     * @param grantResults 相应权限的授予结果是 或 从不为空
+     */
+    @Override
+    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+        if (requestCode == 100) {//权限返回
+            if (!SystemUtil.hasPermission(this, listPermissions).isEmpty()) {
+                finish();
+            } else {
+                String code = "g.deviceData.version='" + GeneralUtil.getVersionName(this) + "';" +
+                        "g.deviceData.channel='" + BuildConfig.TF_CHANNEL + "';" +
+                        "g.deviceData.imei='" + SystemUtil.getIMEI(this) + "';" +
+                        "g.deviceData.oaid='" + OAID + "';" +
+                        "g.deviceData.androId='" + SystemUtil.getAndroidID(this) + "';" +
+                        "g.deviceData.mac='" + SystemUtil.getMac(this) + "';";
+                webView.evaluateJavascript(code, null);
+            }
+        }
+    }
+
+    public static final String TYPE_WXCODE = "wxcode";
+
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        setIntent(intent);
+        String wxCode = intent.getStringExtra(TYPE_WXCODE);
+        if (wxCode != null) {//微信登录返回
+            webView.evaluateJavascript("g.wechatData.code='" + wxCode + "';", null);
+        }
+    }
+}

+ 84 - 0
app/src/main/java/com/aries/jjdz/mz/wxapi/WXEntryActivity.java

@@ -0,0 +1,84 @@
+package com.aries.jjdz.mz.wxapi;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+
+import com.aries.jjdz.mz.MainActivity;
+import com.mokasz.libs.utils.WechatUtil;
+import com.tencent.mm.opensdk.constants.ConstantsAPI;
+import com.tencent.mm.opensdk.modelbase.BaseReq;
+import com.tencent.mm.opensdk.modelbase.BaseResp;
+import com.tencent.mm.opensdk.modelbiz.WXLaunchMiniProgram;
+import com.tencent.mm.opensdk.modelmsg.SendAuth;
+import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;
+
+/**
+ * 该 Activity 为接收微信回跳 处理回调
+ */
+public class WXEntryActivity extends Activity implements IWXAPIEventHandler {
+    private static final int RETURN_MSG_TYPE_LOGIN = 1;
+    private static final int RETURN_MSG_TYPE_SHARE = 2;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        WechatUtil.api.handleIntent(getIntent(), this);
+    }
+
+    @Override
+    public void onReq(BaseReq baseReq) {
+    }
+
+    @Override
+    public void onResp(BaseResp baseResp) {
+        switch (baseResp.errCode) {
+            case BaseResp.ErrCode.ERR_USER_CANCEL:
+            case BaseResp.ErrCode.ERR_AUTH_DENIED:
+                if (RETURN_MSG_TYPE_LOGIN == baseResp.getType()) {
+                }
+                finish();
+                break;
+            case BaseResp.ErrCode.ERR_OK:
+                switch (baseResp.getType()) {
+                    case RETURN_MSG_TYPE_SHARE:
+//                        CocosHelper.runOnGameThread(() -> CocosJavascriptJavaBridge.evalString("g.wechatData.shareSuccess=" + true + ";"));
+                        finish();
+                        break;
+                    case RETURN_MSG_TYPE_LOGIN:
+                        //获取
+                        String code = ((SendAuth.Resp) baseResp).code;
+//                        CocosHelper.runOnGameThread(() -> CocosJavascriptJavaBridge.evalString("g.wechatData.code='" + code + "';"));
+                        Intent intent = new Intent(this, MainActivity.class);
+                        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+                        intent.putExtra(MainActivity.TYPE_WXCODE, code);
+                        startActivity(intent);
+                        finish();
+                        break;
+                    case ConstantsAPI.COMMAND_LAUNCH_WX_MINIPROGRAM:
+                        WXLaunchMiniProgram.Resp launchMiniProResp = (WXLaunchMiniProgram.Resp) baseResp;
+                        String extraData = launchMiniProResp.extMsg;
+                        break;
+                }
+                break;
+            default:
+                finish();
+        }
+    }
+
+    @Override
+    public void onPointerCaptureChanged(boolean hasCapture) {
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+    }
+}

+ 58 - 0
app/src/main/java/com/mokasz/ad/ADReport.java

@@ -0,0 +1,58 @@
+package com.mokasz.ad;
+
+import com.anythink.core.api.ATAdInfo;
+import com.anythink.core.api.AdError;
+
+/**
+ * 广告上报接口
+ */
+public interface ADReport {
+    /**
+     * 视频完播上报
+     *
+     * @param atAdInfo TOPON参数
+     */
+    default String adVideoEndReport(ATAdInfo atAdInfo) {
+        return "g.adData.destoon_ad_place='" + atAdInfo.getTopOnPlacementId() + "';" +
+                "g.adData.adsource_id='" + atAdInfo.getAdsourceId() + "';" +
+                "g.adData.network_firm_id=" + atAdInfo.getNetworkFirmId() + ";" +
+                "g.adData.network_placement_id='" + atAdInfo.getNetworkPlacementId() + "';" +
+                "g.adData.adsource_price=" + atAdInfo.getEcpm() + ";" +
+                "g.adData.network_type='" + atAdInfo.getAdNetworkType() + "';" +
+                "g.adData.adsource_index=" + atAdInfo.getAdsourceIndex() + ";" +
+                "g.adData.adsource_isheaderbidding=" + atAdInfo.isHeaderBiddingAdsource() + ";" +
+                "g.adData.adunit_format='" + atAdInfo.getTopOnAdFormat() + "';" +
+                "g.adData.ecpm_level=" + atAdInfo.getEcpmLevel() + ";" +
+                "g.adData.precision_ecpm='" + atAdInfo.getEcpmPrecision() + "';" +
+                "g.adData.publisher_revenue='" + atAdInfo.getPublisherRevenue() + "';";
+    }
+
+    /**
+     * 广告展示上报
+     *
+     * @param atAdInfo TOPON参数
+     */
+    default String adShowReport(ATAdInfo atAdInfo) {
+        return "g.adData.destoon_ad_place='" + atAdInfo.getTopOnPlacementId() + "';" +
+                "g.adData.adsource_id='" + atAdInfo.getAdsourceId() + "';" +
+                "g.adData.network_firm_id=" + atAdInfo.getNetworkFirmId() + ";" +
+                "g.adData.network_placement_id='" + atAdInfo.getNetworkPlacementId() + "';" +
+                "g.adData.adsource_price=" + atAdInfo.getEcpm() + ";" +
+                "g.adData.network_type='" + atAdInfo.getAdNetworkType() + "';" +
+                "g.adData.adsource_index=" + atAdInfo.getAdsourceIndex() + ";" +
+                "g.adData.adsource_isheaderbidding=" + atAdInfo.isHeaderBiddingAdsource() + ";" +
+                "g.adData.adunit_format='" + atAdInfo.getTopOnAdFormat() + "';" +
+                "g.adData.ecpm_level=" + atAdInfo.getEcpmLevel() + ";" +
+                "g.adData.precision_ecpm='" + atAdInfo.getEcpmPrecision() + "';" +
+                "g.adData.publisher_revenue='" + atAdInfo.getPublisherRevenue() + "';";
+    }
+
+    /**
+     * 广告加载失败上报
+     *
+     * @param adError TOPON参数
+     */
+    default String adLoadFailReport(AdError adError) {
+        return "";
+    }
+}

+ 104 - 0
app/src/main/java/com/mokasz/ad/BannerAD.java

@@ -0,0 +1,104 @@
+package com.mokasz.ad;
+
+import android.app.Activity;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.anythink.banner.api.ATBannerListener;
+import com.anythink.banner.api.ATBannerView;
+import com.anythink.core.api.ATAdInfo;
+import com.anythink.core.api.AdError;
+import com.aries.jjdz.mz.R;
+
+public class BannerAD {
+    private ATBannerView atBannerView;
+    private Activity activity;
+
+    public BannerAD(Activity activity) {
+        this.activity = activity;
+
+        atBannerView = new ATBannerView(activity);
+        atBannerView.setPlacementId(Constants.BANNER_AD_ID);
+        float ratio = 320 / 70f;//必须跟TopOn后台配置的Banner广告源宽高比例一致,假设尺寸为320x50
+        int width = activity.getResources().getDisplayMetrics().widthPixels;//定一个宽度值,比如屏幕宽度
+        int height = (int) (width / ratio);
+        atBannerView.setLayoutParams(new FrameLayout.LayoutParams(width, height));
+        FrameLayout frameLayout = (FrameLayout) activity.findViewById(R.id.banner_container);
+        frameLayout.addView(atBannerView);
+
+        atBannerView.setBannerAdListener(new ATBannerListener() {
+            @Override
+            public void onBannerLoaded() {
+                Log.i("MokaGame", "广告加载成功");
+            }
+
+            @Override
+            public void onBannerFailed(AdError adError) {
+                Log.i("MokaGame", "广告加载出错");
+            }
+
+            @Override
+            public void onBannerClicked(ATAdInfo atAdInfo) {
+
+            }
+
+            @Override
+            public void onBannerShow(ATAdInfo atAdInfo) {
+//                CocosHelper.runOnGameThread(() -> {
+//                    CocosJavascriptJavaBridge.evalString("" +
+//                            "g.adData.ad_type=7;" +
+//                            "g.adData.destoon_ad_place='" + atAdInfo.getTopOnPlacementId() + "';" +
+//                            "g.adData.adsource_id='" + atAdInfo.getAdsourceId() + "';" +
+//                            "g.adData.network_firm_id=" + atAdInfo.getNetworkFirmId() + ";" +
+//                            "g.adData.network_placement_id='" + atAdInfo.getNetworkPlacementId() + "';" +
+//                            "g.adData.adsource_price=" + atAdInfo.getEcpm() + ";" +
+//                            "g.adData.network_type='" + atAdInfo.getAdNetworkType() + "';" +
+//                            "g.adData.adsource_index=" + atAdInfo.getAdsourceIndex() + ";" +
+//                            "g.adData.adsource_isheaderbidding=" + atAdInfo.isHeaderBiddingAdsource() + ";" +
+//                            "g.adData.adunit_format='" + atAdInfo.getTopOnAdFormat() + "';" +
+//                            "g.adData.ecpm_level=" + atAdInfo.getEcpmLevel() + ";" +
+//                            "g.adData.precision_ecpm='" + atAdInfo.getEcpmPrecision() + "';" +
+//                            "g.adData.publisher_revenue='" + atAdInfo.getPublisherRevenue() + "';" +
+//                            "g.adData.bannerADShow=true;");
+//                });
+            }
+
+            @Override
+            public void onBannerClose(ATAdInfo atAdInfo) {
+                Log.i("MokaGame", "广告加载关闭");
+                atBannerView.setVisibility(View.GONE);
+            }
+
+            @Override
+            public void onBannerAutoRefreshed(ATAdInfo atAdInfo) {
+
+            }
+
+            @Override
+            public void onBannerAutoRefreshFail(AdError adError) {
+
+            }
+        });
+        load();
+    }
+
+    public void load() {
+        atBannerView.loadAd();
+    }
+
+    public void hide() {
+        atBannerView.setVisibility(View.GONE);
+    }
+
+    public void show() {
+        atBannerView.setVisibility(View.VISIBLE);
+    }
+
+    public void removeAD() {
+        if (atBannerView != null && atBannerView.getParent() != null) {
+            ((ViewGroup) atBannerView.getParent()).removeView(atBannerView);
+        }
+    }
+}

+ 19 - 0
app/src/main/java/com/mokasz/ad/Constants.java

@@ -0,0 +1,19 @@
+package com.mokasz.ad;
+
+import com.aries.jjdz.mz.BuildConfig;
+import com.mokasz.libs.utils.GeneralUtil;
+
+/**
+ * 获取自定义参数
+ */
+public class Constants {
+    private static String allParam = BuildConfig.TOPON;
+    public static String APP_ID = GeneralUtil.splitStr(allParam, ",")[0];
+    public static String APP_KEY = GeneralUtil.splitStr(allParam, ",")[1];
+    public static String REWARD_AD_ID = GeneralUtil.splitStr(allParam, ",")[2];
+    public static String INTERSTITIAL_AD_ID = GeneralUtil.splitStr(allParam, ",")[3];
+    public static String NATIVE_AD_ID = GeneralUtil.splitStr(allParam, ",")[4];
+    public static String SPLASH_AD_ID = GeneralUtil.splitStr(allParam, ",")[5];
+    public static String BANNER_AD_ID = GeneralUtil.splitStr(allParam, ",")[6];
+    public static String FULLSCREEN_AD_ID = GeneralUtil.splitStr(allParam, ",")[7];
+}

+ 67 - 0
app/src/main/java/com/mokasz/ad/InterstitialAD.java

@@ -0,0 +1,67 @@
+package com.mokasz.ad;
+
+import android.app.Activity;
+
+import com.anythink.core.api.ATAdInfo;
+import com.anythink.core.api.AdError;
+import com.anythink.interstitial.api.ATInterstitial;
+import com.anythink.interstitial.api.ATInterstitialListener;
+import com.mokasz.libs.utils.ToastUtil;
+
+public class InterstitialAD implements ATInterstitialListener, ADReport {
+    private final ATInterstitial atInterstitial;
+    private Activity activity;
+
+    public InterstitialAD(Activity activity,boolean isFullScreen) {
+        this.activity = activity;
+        this.atInterstitial = new ATInterstitial(activity, isFullScreen ? Constants.FULLSCREEN_AD_ID : Constants.INTERSTITIAL_AD_ID);
+        atInterstitial.setAdListener(this);
+        this.atInterstitial.load();//初次广告加载
+    }
+
+    public void showAD() {
+        if (atInterstitial.isAdReady()) {
+            atInterstitial.show(activity);
+        } else if (!atInterstitial.checkAdStatus().isLoading()) {
+            atInterstitial.load();
+//            CocosHelper.runOnGameThread(() -> CocosJavascriptJavaBridge.evalString("g.onRewardVideoADLoss()"));
+            ToastUtil.showToast(activity, "视频加载中,请稍后重试!");
+        }
+    }
+
+    @Override
+    public void onInterstitialAdLoaded() {
+    }
+
+    @Override
+    public void onInterstitialAdLoadFail(AdError adError) {
+        String string = adLoadFailReport(adError);
+    }
+
+    @Override
+    public void onInterstitialAdClicked(ATAdInfo atAdInfo) {
+    }
+
+    @Override
+    public void onInterstitialAdShow(ATAdInfo atAdInfo) {
+        String string = adShowReport(atAdInfo);
+    }
+
+    @Override
+    public void onInterstitialAdClose(ATAdInfo atAdInfo) {
+        atInterstitial.load();
+    }
+
+    @Override
+    public void onInterstitialAdVideoStart(ATAdInfo atAdInfo) {
+    }
+
+    @Override
+    public void onInterstitialAdVideoEnd(ATAdInfo atAdInfo) {
+        String string = adVideoEndReport(atAdInfo);
+    }
+
+    @Override
+    public void onInterstitialAdVideoError(AdError adError) {
+    }
+}

+ 144 - 0
app/src/main/java/com/mokasz/ad/NativeExpressAD.java

@@ -0,0 +1,144 @@
+package com.mokasz.ad;
+
+import android.app.Activity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.anythink.core.api.ATAdConst;
+import com.anythink.core.api.ATAdInfo;
+import com.anythink.core.api.AdError;
+import com.anythink.nativead.api.ATNative;
+import com.anythink.nativead.api.ATNativeAdView;
+import com.anythink.nativead.api.ATNativeDislikeListener;
+import com.anythink.nativead.api.ATNativeEventExListener;
+import com.anythink.nativead.api.ATNativeNetworkListener;
+import com.anythink.nativead.api.NativeAd;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 原生信息流广告
+ */
+public class NativeExpressAD {
+    ATNative atNative;
+    ATNativeAdView atNativeAdView;
+    NativeAd nativeAd;
+
+    ViewGroup viewGroup;
+    Activity activity;
+
+    public NativeExpressAD(ViewGroup viewGroup, Activity activity) {
+        this.viewGroup = viewGroup;
+        this.activity = activity;
+    }
+
+    public void initNativeAd() {
+        atNative = new ATNative(activity, Constants.NATIVE_AD_ID, new ATNativeNetworkListener() {
+            @Override
+            public void onNativeAdLoaded() {
+                showNativeAD();
+            }
+
+            @Override
+            public void onNativeAdLoadFail(AdError adError) {
+//                CocosHelper.runOnGameThread(() -> CocosJavascriptJavaBridge.evalString("g.adData.nativeExpressADError=true"));
+            }
+        });
+        if (atNativeAdView == null) {
+            atNativeAdView = new ATNativeAdView(activity);
+        }
+    }
+
+    public int adViewWidth, adViewHeight;
+
+    public void loadNativeAd() {
+        if (atNative != null) {
+            adViewWidth = activity.getResources().getDisplayMetrics().widthPixels;
+            adViewHeight = dip2px(300);
+            ViewGroup.LayoutParams pp = this.viewGroup.getLayoutParams();
+            pp.height = adViewHeight;
+            this.viewGroup.setLayoutParams(pp);
+
+            Map<String, Object> localMap = new HashMap<>();
+            localMap.put(ATAdConst.KEY.AD_WIDTH, adViewWidth);
+            localMap.put(ATAdConst.KEY.AD_HEIGHT, adViewHeight);
+
+            atNative.setLocalExtra(localMap);
+            atNative.makeAdRequest();
+        }
+    }
+
+    public void showNativeAD() {
+        if (this.atNative == null) {
+            return;
+        }
+        NativeAd nativeAd = atNative.getNativeAd();
+        if (nativeAd != null && atNativeAdView != null) {
+            atNativeAdView.removeAllViews();
+            if (atNativeAdView.getParent() == null) {//添加进入容器
+                viewGroup.addView(atNativeAdView, new FrameLayout.LayoutParams(adViewWidth, adViewHeight));
+            }
+        }
+
+        this.nativeAd = nativeAd;
+        this.nativeAd.setNativeEventListener(new ATNativeEventExListener() {
+            @Override
+            public void onDeeplinkCallback(ATNativeAdView atNativeAdView, ATAdInfo atAdInfo, boolean b) {
+            }
+
+            @Override
+            public void onAdImpressed(ATNativeAdView atNativeAdView, ATAdInfo atAdInfo) {
+//                CocosHelper.runOnGameThread(() -> CocosJavascriptJavaBridge.evalString("g.adData.ad_type=3;" +
+//                        "g.adData.destoon_ad_place='" + atAdInfo.getTopOnPlacementId() + "';" +
+//                        "g.adData.adsource_id='" + atAdInfo.getAdsourceId() + "';" +
+//                        "g.adData.network_firm_id=" + atAdInfo.getNetworkFirmId() + ";" +
+//                        "g.adData.network_placement_id='" + atAdInfo.getNetworkPlacementId() + "';" +
+//                        "g.adData.adsource_price=" + atAdInfo.getEcpm() + ";" +
+//                        "g.adData.network_type='" + atAdInfo.getAdNetworkType() + "';" +
+//                        "g.adData.adsource_index=" + atAdInfo.getAdsourceIndex() + ";" +
+//                        "g.adData.adsource_isheaderbidding=" + atAdInfo.isHeaderBiddingAdsource() + ";" +
+//                        "g.adData.adunit_format='" + atAdInfo.getTopOnAdFormat() + "';" +
+//                        "g.adData.ecpm_level=" + atAdInfo.getEcpmLevel() + ";" +
+//                        "g.adData.precision_ecpm='" + atAdInfo.getEcpmPrecision() + "';" +
+//                        "g.adData.publisher_revenue=" + atAdInfo.getPublisherRevenue() + ";" +
+//                        "g.adData.nativeExpressADShow=true;"));
+            }
+
+            @Override
+            public void onAdClicked(ATNativeAdView atNativeAdView, ATAdInfo atAdInfo) {
+            }
+
+            @Override
+            public void onAdVideoStart(ATNativeAdView atNativeAdView) {
+            }
+
+            @Override
+            public void onAdVideoEnd(ATNativeAdView atNativeAdView) {
+            }
+
+            @Override
+            public void onAdVideoProgress(ATNativeAdView atNativeAdView, int i) {
+            }
+        });
+        this.nativeAd.setDislikeCallbackListener(new ATNativeDislikeListener() {
+            @Override
+            public void onAdCloseButtonClick(ATNativeAdView atNativeAdView, ATAdInfo atAdInfo) {
+                viewGroup.setVisibility(View.GONE);
+            }
+        });
+        NativeRender render = new NativeRender(activity);
+        this.nativeAd.renderAdView(atNativeAdView, render);
+        this.nativeAd.prepare(atNativeAdView, render.getClickView(), null);
+    }
+
+    public int dip2px(float dipValue) {
+        float scale = activity.getResources().getDisplayMetrics().density;
+        return (int) (dipValue * scale + 0.5f);
+    }
+
+    public void changeAD(){
+        atNative.makeAdRequest();
+    }
+}

+ 213 - 0
app/src/main/java/com/mokasz/ad/NativeRender.java

@@ -0,0 +1,213 @@
+package com.mokasz.ad;
+
+import android.content.Context;
+import android.text.Html;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.anythink.nativead.api.ATNativeAdRenderer;
+import com.anythink.nativead.api.ATNativeImageView;
+import com.anythink.nativead.api.NativeAdInteractionType;
+import com.anythink.nativead.unitgroup.api.CustomNativeAd;
+import com.aries.jjdz.mz.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class NativeRender implements ATNativeAdRenderer<CustomNativeAd> {
+
+    Context mContext;
+    List<View> mClickView = new ArrayList<>();
+    List<View> mClickDownloadDirectViews = new ArrayList<>();
+    View mCloseView;
+
+    boolean isSelfHandleDownloadConfirm;
+
+    public NativeRender(Context context) {
+        mContext = context;
+    }
+
+    public void setWhetherSettingDownloadConfirmListener(boolean isSelfHandle) {
+        isSelfHandleDownloadConfirm = isSelfHandle;
+    }
+
+    View mDevelopView;
+
+    int mNetworkType;
+
+    @Override
+    public View createView(Context context, int networkType) {
+        if (mDevelopView == null) {
+            mDevelopView = LayoutInflater.from(context).inflate(R.layout.native_ad_item, null);
+        }
+        mNetworkType = networkType;
+        if (mDevelopView.getParent() != null) {
+            ((ViewGroup) mDevelopView.getParent()).removeView(mDevelopView);
+        }
+        return mDevelopView;
+    }
+
+    @Override
+    public void renderAdView(View view, CustomNativeAd ad) {
+        List<View> customDownloadViews = new ArrayList<>();
+        mClickView.clear();
+        TextView titleView = (TextView) view.findViewById(R.id.native_ad_title);
+        TextView descView = (TextView) view.findViewById(R.id.native_ad_desc);
+        TextView ctaView = (TextView) view.findViewById(R.id.native_ad_install_btn);
+        TextView adFromView = (TextView) view.findViewById(R.id.native_ad_from);
+        FrameLayout contentArea = (FrameLayout) view.findViewById(R.id.native_ad_content_image_area);
+        FrameLayout iconArea = (FrameLayout) view.findViewById(R.id.native_ad_image);
+        final ATNativeImageView logoView = (ATNativeImageView) view.findViewById(R.id.native_ad_logo);
+        View versionArea = view.findViewById(R.id.native_ad_version_area);
+        TextView versionTextView = view.findViewById(R.id.native_ad_version);
+        versionTextView.setText(Html.fromHtml("<u>" + "版本" + "</u>"));
+
+
+        if (mNetworkType == 8 && isSelfHandleDownloadConfirm) {
+            customDownloadViews.add(versionTextView);
+            versionTextView.setVisibility(View.VISIBLE);
+        } else {
+            versionTextView.setVisibility(View.GONE);
+        }
+        customDownloadViews.add(ctaView);
+
+        CustomNativeAd.ExtraInfo extraInfo = new CustomNativeAd.ExtraInfo.Builder()
+                .setCloseView(mCloseView)
+                .setCustomViewList(customDownloadViews)
+                .build();
+
+        ad.setExtraInfo(extraInfo);
+
+        mClickDownloadDirectViews = new ArrayList<>();
+        if (mNetworkType == 8 || mNetworkType == 22) {
+            mClickDownloadDirectViews.add(ctaView);
+        } else {
+            mClickView.add(ctaView);
+        }
+
+
+        titleView.setText("");
+        descView.setText("");
+        ctaView.setText("");
+        adFromView.setText("");
+        titleView.setText("");
+        contentArea.removeAllViews();
+        iconArea.removeAllViews();
+        logoView.setImageDrawable(null);
+
+        View mediaView = ad.getAdMediaView(contentArea, contentArea.getWidth());
+
+        Log.i("NativeDemoRender", "Ad Interaction type:" + (ad.getNativeAdInteractionType() == NativeAdInteractionType.APP_TYPE ? "Application" : "UNKNOW"));
+
+        if (ad.isNativeExpress()) {// 模板渲染(个性化模板、自动渲染)
+            titleView.setVisibility(View.GONE);
+            descView.setVisibility(View.GONE);
+            ctaView.setVisibility(View.GONE);
+            logoView.setVisibility(View.GONE);
+            iconArea.setVisibility(View.GONE);
+            if (mCloseView != null) {
+                mCloseView.setVisibility(View.GONE);
+            }
+            if (mediaView.getParent() != null) {
+                ((ViewGroup) mediaView.getParent()).removeView(mediaView);
+            }
+            versionArea.setVisibility(View.GONE);
+
+            contentArea.addView(mediaView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT));
+            return;
+        }
+
+        // 自渲染(自定义渲染)
+
+        titleView.setVisibility(View.VISIBLE);
+        descView.setVisibility(View.VISIBLE);
+        ctaView.setVisibility(View.VISIBLE);
+        logoView.setVisibility(View.VISIBLE);
+        iconArea.setVisibility(View.VISIBLE);
+        versionArea.setVisibility(View.VISIBLE);
+        if (mCloseView != null) {
+            mCloseView.setVisibility(View.VISIBLE);
+        }
+        View adiconView = ad.getAdIconView();
+
+
+        final ATNativeImageView iconView = new ATNativeImageView(mContext);
+        if (adiconView == null) {
+            iconArea.addView(iconView);
+            iconView.setImage(ad.getIconImageUrl());
+            mClickView.add(iconView);
+        } else {
+            iconArea.addView(adiconView);
+        }
+
+
+        if (!TextUtils.isEmpty(ad.getAdChoiceIconUrl())) {
+            logoView.setImage(ad.getAdChoiceIconUrl());
+        } else {
+//            logoView.setImageResource(R.drawable.ad_logo);
+        }
+
+
+        if (mediaView != null) {
+            if (mediaView.getParent() != null) {
+                ((ViewGroup) mediaView.getParent()).removeView(mediaView);
+            }
+
+            contentArea.addView(mediaView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
+
+        } else {
+
+            ATNativeImageView imageView = new ATNativeImageView(mContext);
+            imageView.setImage(ad.getMainImageUrl());
+
+            ViewGroup.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
+            imageView.setLayoutParams(params);
+            contentArea.addView(imageView, params);
+
+            mClickView.add(imageView);
+        }
+
+        titleView.setText(ad.getTitle());
+        descView.setText(ad.getDescriptionText());
+
+        if (!TextUtils.isEmpty(ad.getCallToActionText())) {
+            ctaView.setVisibility(View.VISIBLE);
+            ctaView.setText(ad.getCallToActionText());
+        } else {
+            ctaView.setVisibility(View.GONE);
+        }
+
+
+        if (!TextUtils.isEmpty(ad.getAdFrom())) {
+            adFromView.setText(ad.getAdFrom() != null ? ad.getAdFrom() : "");
+            adFromView.setVisibility(View.VISIBLE);
+        } else {
+            adFromView.setVisibility(View.GONE);
+        }
+
+        mClickView.add(titleView);
+        mClickView.add(descView);
+
+
+    }
+
+    public List<View> getClickView() {
+        return mClickView;
+    }
+
+    public void setCloseView(ImageView closeView) {
+        this.mCloseView = closeView;
+
+    }
+
+    public List<View> getDownloadDirectViews() {
+        return mClickDownloadDirectViews;
+    }
+}

+ 75 - 0
app/src/main/java/com/mokasz/ad/RewardVideoAD.java

@@ -0,0 +1,75 @@
+package com.mokasz.ad;
+
+import android.app.Activity;
+
+import com.anythink.core.api.ATAdInfo;
+import com.anythink.core.api.AdError;
+import com.anythink.rewardvideo.api.ATRewardVideoAd;
+import com.anythink.rewardvideo.api.ATRewardVideoExListener;
+import com.mokasz.libs.utils.ToastUtil;
+
+public class RewardVideoAD implements ATRewardVideoExListener, ADReport {
+    private final ATRewardVideoAd atRewardVideoAd;
+    private Activity activity;
+
+    public RewardVideoAD(Activity activity) {
+        this.activity = activity;
+        this.atRewardVideoAd = new ATRewardVideoAd(RewardVideoAD.this.activity, Constants.REWARD_AD_ID);
+        this.atRewardVideoAd.load();
+    }
+
+    /**
+     * 展示激励
+     */
+    public void showRewardVideoAD() {
+        if (atRewardVideoAd.isAdReady()) {
+            atRewardVideoAd.show(activity);
+        } else if (!atRewardVideoAd.isAdReady()) {
+            atRewardVideoAd.load();
+//            CocosHelper.runOnGameThread(() -> CocosJavascriptJavaBridge.evalString("g.onRewardVideoADLoss()"));
+            ToastUtil.showToast(activity, "视频加载中,请稍后重试");
+        }
+    }
+
+    @Override
+    public void onDeeplinkCallback(ATAdInfo atAdInfo, boolean b) {
+    }
+
+    @Override
+    public void onRewardedVideoAdLoaded() {
+
+    }
+
+    @Override
+    public void onRewardedVideoAdFailed(AdError adError) {
+        String string = adLoadFailReport(adError);
+    }
+
+    @Override
+    public void onRewardedVideoAdPlayStart(ATAdInfo atAdInfo) {
+        String string = adShowReport(atAdInfo);
+    }
+
+    @Override
+    public void onRewardedVideoAdPlayEnd(ATAdInfo atAdInfo) {
+        String string = adVideoEndReport(atAdInfo);
+    }
+
+    @Override
+    public void onRewardedVideoAdPlayFailed(AdError adError, ATAdInfo atAdInfo) {
+    }
+
+    @Override
+    public void onRewardedVideoAdClosed(ATAdInfo atAdInfo) {
+//        JavaScriptBridge.executeJS(string + "g.adData.rewardVideoADComplete=true;");
+        atRewardVideoAd.load();
+    }
+
+    @Override
+    public void onRewardedVideoAdPlayClicked(ATAdInfo atAdInfo) {
+    }
+
+    @Override
+    public void onReward(ATAdInfo atAdInfo) {
+    }
+}

+ 72 - 0
app/src/main/java/com/mokasz/ad/SplashADActivity.java

@@ -0,0 +1,72 @@
+package com.mokasz.ad;//package com.mokasz.ad;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.widget.FrameLayout;
+
+import com.anythink.core.api.ATAdInfo;
+import com.anythink.core.api.AdError;
+import com.anythink.splashad.api.ATSplashAd;
+import com.anythink.splashad.api.ATSplashAdListener;
+import com.aries.jjdz.mz.R;
+
+public class SplashADActivity extends Activity implements ATSplashAdListener, ADReport {
+    private FrameLayout content = null;
+
+    private ATSplashAd atSplashAd = null;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.splash_ad);
+
+        this.content = findViewById(R.id.splash_content);
+        atSplashAd = new ATSplashAd(this, Constants.SPLASH_AD_ID, this);
+        if (atSplashAd.isAdReady()) {
+            atSplashAd.show(this, content);
+        } else {
+            atSplashAd.loadAd();
+        }
+    }
+
+    @Override
+    public void onAdLoaded() {
+        atSplashAd.show(this, content);
+    }
+
+    @Override
+    public void onNoAdError(AdError adError) {
+        String string = adLoadFailReport(adError);
+        jumpToMainActivity();
+    }
+
+    @Override
+    public void onAdShow(ATAdInfo atAdInfo) {
+        String string = adShowReport(atAdInfo);
+    }
+
+    @Override
+    public void onAdClick(ATAdInfo atAdInfo) {
+    }
+
+    @Override
+    public void onAdDismiss(ATAdInfo atAdInfo) {
+        jumpToMainActivity();
+    }
+
+    /**
+     * 跳转游戏
+     */
+    public void jumpToMainActivity() {
+        finish();
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (atSplashAd != null) {
+            atSplashAd.onDestory();
+        }
+    }
+}

+ 109 - 0
app/src/main/java/com/mokasz/libs/DownLoadHandler.java

@@ -0,0 +1,109 @@
+package com.mokasz.libs;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Message;
+import android.support.v4.content.FileProvider;
+import android.util.Log;
+import android.webkit.WebView;
+
+import com.liulishuo.filedownloader.util.FileDownloadUtils;
+import com.mokasz.libs.utils.FileUtil;
+import com.mokasz.libs.utils.OkhttpUtil;
+
+import java.io.File;
+import java.io.IOException;
+
+public class DownLoadHandler extends Handler {
+    private Context context;
+
+    DownLoadHandler(Context c) {
+        context = c;
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        super.handleMessage(msg);
+        String[] args;
+        WebView webView = ((MOKActivity) context).webView;
+        switch (msg.what) {
+            case OkhttpUtil.DOWNLOAD_FAIL:
+                webView.evaluateJavascript("g.deviceData.downLoadFail = '" + msg.what + "'", null);
+                break;
+            case OkhttpUtil.DOWNLOAD_PROGRESS:
+                webView.evaluateJavascript("g.deviceData.downLoadProgress = " + msg.obj, null);
+                break;
+            case OkhttpUtil.DOWNLOAD_SUCCESS:
+                args = msg.obj.toString().split("\\|");
+                final String filePath = args[0];
+                final String extension = args[1];
+                if (extension.equals("apk")) {//安装apk
+                    File file = new File(filePath);
+                    if (!file.exists()) {
+                        return;
+                    }
+                    String[] command = {"chmod", "777", file.toString()};
+                    ProcessBuilder builder = new ProcessBuilder(command);
+                    try {
+                        builder.start();
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                    Intent intent = new Intent(Intent.ACTION_VIEW);
+                    // 由于没有在Activity环境下启动Activity,设置下面的标签
+                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//android 7.0
+                        Uri apkUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file);
+                        //添加这一句表示对目标应用临时授权该Uri所代表的文件
+                        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+                        intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
+                    } else {
+                        intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
+                    }
+                    context.startActivity(intent);
+                } else if (extension.equals("zip")) {
+                    final File gameDir = new File(context.getExternalFilesDir(null) + "/game");
+                    final String version = args[2];
+                    final ZipExtractorTask zipTask = new ZipExtractorTask(filePath, gameDir.getPath(), true, new ZipExtractorListener() {
+                        @Override
+                        public void onReady() {
+//                            webView.evaluateJavascript("window.unzipStart = true", null);
+                            Log.i("MokaGame", "准备解压");
+                        }
+
+                        @Override
+                        public void onComplete() {
+                            Log.i("MokaGame", "解压完成");
+                            String versionPath = gameDir.getPath() + "/version";
+                            final String indexPath = gameDir + "/" + "index.html";
+                            if (FileUtil.isFileExist(indexPath)) {//下载成功
+                                FileUtil.writeFile(version, versionPath, false);
+                                Log.i("MokaGame", "解压完成,准备进入");
+                                webView.clearCache(true);//清除缓存,防止页面刷新还是老的代码
+//                                webView.evaluateJavascript("window.unzipComplete = '" + indexPath + "'", null);
+                                new File(filePath).delete();//删除压缩包
+                                new File(FileDownloadUtils.getTempPath(filePath)).delete();//删除压缩包
+                            } else {//下载失败
+                                Log.w("MokaGame", "解压失败,文件不存在");
+//                                webView.evaluateJavascript("window.unzipFail = '解压失败,文件不存在'", null);
+                            }
+                        }
+
+                        @Override
+                        public void onProgress(int sofar, int total) {
+                            Log.i("MokaGame", "解压进度 " + sofar + "/" + total);
+                            int progress = (int) (sofar * 1.0f / total * 100);
+//                            webView.evaluateJavascript("window.unzipProgress = " + progress, null);
+                        }
+                    });
+                    zipTask.execute();
+                }
+                break;
+            default:
+                break;
+        }
+    }
+}

+ 194 - 0
app/src/main/java/com/mokasz/libs/MOKActivity.java

@@ -0,0 +1,194 @@
+package com.mokasz.libs;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.net.http.SslError;
+import android.os.Build;
+import android.os.Bundle;
+import android.provider.MediaStore;
+import android.support.annotation.Nullable;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.webkit.SslErrorHandler;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebResourceResponse;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+
+
+import com.aries.jjdz.mz.R;
+import com.liulishuo.filedownloader.FileDownloader;
+import com.smarx.notchlib.INotchScreen;
+import com.smarx.notchlib.NotchScreenManager;
+import com.smarx.notchlib.utils.ScreenUtil;
+
+import ren.yale.android.cachewebviewlib.ResourceInterceptor;
+import ren.yale.android.cachewebviewlib.WebViewCacheInterceptor;
+import ren.yale.android.cachewebviewlib.WebViewCacheInterceptorInst;
+import ren.yale.android.cachewebviewlib.config.CacheExtensionConfig;
+
+public class MOKActivity extends Activity {
+    public WebView webView;
+    public DownLoadHandler downLoadHandler = null;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        //解决全屏Activity的键盘档住输入框
+        SoftKeyboardFixerForFullscreen.assistActivity(this);
+        //刘海屏全屏
+        NotchScreenManager.getInstance().setDisplayInNotch(this);
+        //注册下载器
+        FileDownloader.setup(this);
+        //创建监听
+        createHandler();
+    }
+
+    //加载webview
+    protected WebView createWebView(String url) {
+//        webView = new WebView(this);
+//        this.initSettings();
+//        this.initClient();
+//        webView.loadUrl(url);
+//        LinearLayout container = (LinearLayout)findViewById(R.id.webview_container);
+//        container.addView(webView);
+//        webView.setVisibility(View.INVISIBLE);
+        webView = (WebView) findViewById(R.id.webview);
+        this.initSettings();
+        this.initClient();
+        webView.loadUrl(url);
+        webView.setVisibility(View.INVISIBLE);
+        return webView;
+    }
+
+    /**
+     * 重启应用
+     */
+    public void restart() {
+        webView.reload();
+    }
+
+    protected void initSettings() {
+        webView.setBackgroundColor(0);
+        webView.getSettings().setDomStorageEnabled(true);
+//        webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
+//        webView.getSettings().setAppCacheEnabled(false);//不需要缓存
+        webView.getSettings().setJavaScriptEnabled(true);
+        webView.getSettings().setAllowFileAccess(true);
+        webView.getSettings().setAllowFileAccessFromFileURLs(true);
+        webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
+        webView.getSettings().setAllowContentAccess(true);
+        webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
+        webView.getSettings().setMediaPlaybackRequiresUserGesture(false);
+        //自定义缓存
+//        WebViewCacheInterceptor.Builder builder = new WebViewCacheInterceptor.Builder(this);
+//        CacheExtensionConfig extension = new CacheExtensionConfig();
+//        extension.addExtension("json").addExtension("anim").addExtension("atlas").addExtension("mp3");//添加删除缓存后缀
+//        builder.setCacheExtensionConfig(extension).setCacheSize(1024 * 1024 * 500);
+//        WebViewCacheInterceptorInst.getInstance().
+//                init(builder);
+    }
+
+    private boolean isFirstPageFinished = false;
+
+    protected void onGameCreated() {
+        Log.i("MokaGame", "游戏初始化完成!");
+    }
+
+    private ValueCallback<Uri[]> mFilePathCallback;
+    private static final int REQUEST_CODE_ALBUM = 1;
+
+    public void showWebview() {
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                webView.setVisibility(View.VISIBLE);
+            }
+        });
+    }
+
+    protected void initClient() {
+        webView.setWebViewClient(new WebViewClient() {
+
+            @Override
+            public void onPageStarted(WebView view, String url, Bitmap favicon) {
+                super.onPageStarted(view, url, favicon);
+            }
+
+            @Override
+            public void onPageFinished(WebView view, String url) {
+                super.onPageFinished(view, url);
+                if (!isFirstPageFinished) {
+                    onGameCreated();
+                    isFirstPageFinished = true;
+                }
+            }
+
+            @Override
+            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
+                //handler.cancel(); // Android默认的处理方式
+                handler.proceed();  // 接受所有网站的证书
+                //handleMessage(Message msg); // 进行其他处理
+            }
+
+//            @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+//            @Nullable
+//            @Override
+//            public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
+//                return WebViewCacheInterceptorInst.getInstance().interceptRequest(request);
+//            }
+//
+//            @Nullable
+//            @Override
+//            public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
+//                return WebViewCacheInterceptorInst.getInstance().interceptRequest(url);
+//            }
+        });
+        webView.setWebChromeClient(new WebChromeClient() {
+            //For Android5.0+
+            public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
+                if (mFilePathCallback != null) {
+                    mFilePathCallback.onReceiveValue(null);
+                }
+                mFilePathCallback = filePathCallback;
+//                showChooserDialog();
+                Intent albumIntent = new Intent(Intent.ACTION_PICK);
+                albumIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
+                startActivityForResult(albumIntent, REQUEST_CODE_ALBUM);
+                return true;
+            }
+        });
+    }
+
+    protected void createHandler() {
+        downLoadHandler = new DownLoadHandler(this);
+    }
+
+    @Override
+    public void onBackPressed() {
+        //屏蔽back键
+    }
+
+    protected void onResume() {
+        super.onResume();
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+    }
+
+    protected void onPause() {
+        super.onPause();
+        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+    }
+}

+ 229 - 0
app/src/main/java/com/mokasz/libs/SoftKeyboardFixerForFullscreen.java

@@ -0,0 +1,229 @@
+package com.mokasz.libs;
+
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+/**
+ * 解决全屏Activity的键盘档住输入框
+ * 来自:https://blog.csdn.net/passerby_b/article/details/82686662
+ * 注意:
+ * 1.要在setContentView之后调用 assistActivity(activity)!
+ * 2.要是横屏输入法不是满屏的,就需要自己适配了!
+ * 3.自测没有发现问题,但无法100%保证兼容性~
+ * 4.分屏模式下的处理,不知道会不会有其他问题,如果不是刚需,建议还是通过setSoftInputMode尝试调整~~~
+ * <p>
+ * 更新 Cooper 2018-9-13 13:27:59
+ * 1.解决虚拟导航栏隐藏显示布局不自动适配的问题(三星Note8 8.0实测横屏竖屏都没问题,Vivo没有虚拟按键的机器6.0测试没有问题)
+ * 2.解决分屏模式下不适配的问题(三星Note8 8.0实测横屏竖屏都没问题)
+ * 3.优化代码
+ * <p>
+ * 参考:https://blog.csdn.net/smileiam/article/details/69055963
+ * 参考:https://blog.csdn.net/auccy/article/details/80632429
+ * 参考:https://github.com/yy1300326388/AndroidBarUtils/blob/master/app/src/main/java/cn/zsl/androidbarutils/utils/AndroidBarUtils.java
+ * 其实最初的原版就是 AndroidBug5497Workaround ,但是原版考虑的不够全面,尤其是虚拟导航栏的问题,没有考虑进去
+ * 参考:https://www.jianshu.com/p/a95a1b84da11
+ */
+
+public class SoftKeyboardFixerForFullscreen {
+    public static void assistActivity(Activity activity) {
+        new SoftKeyboardFixerForFullscreen(activity);
+    }
+
+    private View mContentView;//我们设置的contentView
+    private FrameLayout.LayoutParams mFrameLayoutParams;//我们设置的contentView的layoutParams
+
+//    private boolean isNavigationShowing = false;//没有用到这个
+//    private boolean isFullscreenMode = false;//没有用到这个
+//    private int barNavigationHeight = 0;//虚拟导航栏高度,没用
+//    private int barNavigationWidth = 0;//虚拟导航栏宽度,没用
+
+    private int barStatusHeight = 0;//状态栏高度
+
+    private int lastUsableHeight = 0;//上一次的可用高度
+    private int lastUsableWidth = 0;//上一次的可用宽度
+
+    private SoftKeyboardFixerForFullscreen(final Activity activity) {
+        //region 本来是想通过这个监听虚拟按键,结果发现这个回调比布局回调要晚,所以不用了。放在这里是为了给以后提供一些思路。
+//        //1.为DecorView添加系统组件的可见变更事件
+//        View decorView = activity.getWindow().getDecorView();
+//        isNavigationShowing = ((decorView.getSystemUiVisibility() & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0);
+//        isFullscreenMode = ((decorView.getSystemUiVisibility() & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0);//api 16以上
+//        decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {//参考:https://blog.csdn.net/auccy/article/details/80632429
+//            @Override
+//            public void onSystemUiVisibilityChange(int visibility) {
+//                if ((visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
+//                    isNavigationShowing = true;
+//                } else {
+//                    isNavigationShowing = false;
+//                }
+//                if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
+//                    isFullscreenMode = true;
+//                } else {
+//                    isFullscreenMode = true;
+//                }
+//            }
+//        });
+        //endregion
+        //1.获取 状态栏 高度,获取 导航栏 高度、宽度(横屏用到的,可是横屏在手机上输入法会满屏,不知道不满屏的情况,所以不处理了,要是你遇到了,自行按照横屏的方式解决吧)
+        barStatusHeight = getStatusBarHeight(activity);
+        //barNavigationHeight = getNavigationBarHeight(activity);
+        //barNavigationWidth = getNavigationBarWidth(activity);
+        //2.找到Activity的最外层布局控件,它其实是一个DecorView,它所用的控件就是FrameLayout
+        final FrameLayout content = activity.findViewById(android.R.id.content);
+        //3.获取到setContentView放进去的View
+        mContentView = content.getChildAt(0);
+        //4.拿到我们设置的View的布局参数,主要是调整该参数来实现软键盘弹出上移
+        mFrameLayoutParams = (FrameLayout.LayoutParams) mContentView.getLayoutParams();
+        //5.给我们设置的View添加布局变动的监听,来实现布局动作(虚拟导航栏的弹出收起也会触发该监听!)
+        mContentView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+            public void onGlobalLayout() {//软键盘弹出、系统导航栏隐藏显示均会触发这里
+                int heightRoot = content.getRootView().getHeight();//包含虚拟按键的高度(如果有的话)
+                int heightDecor = content.getHeight();//不含虚拟按键的高度,貌似不包含状态栏高度
+
+                int usableHeight = computeUsableHeight();//我们setContentView设置的view的可用高度
+
+                if (usableHeight != lastUsableHeight) {
+                    lastUsableHeight = usableHeight;//防止重复变动
+
+                    int heightDifference = heightDecor - usableHeight;
+
+                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && activity.isInMultiWindowMode()) {//如果是分屏模式
+                        if (heightDifference > 0) {//分屏模式,只要变动了就人为弹出键盘,因为分屏可能该Activity是在手机屏幕的上方,弹出输入法只是遮盖了一丁点~如果不合适,需要你自己适配了!
+                            setHeight(heightDecor - heightDifference); //这里不能加状态栏高度哟~
+                        } else {
+                            setHeight(FrameLayout.LayoutParams.MATCH_PARENT);//还原默认高度,不能用计算的值,因为虚拟导航栏显示或者隐藏的时候也会改变高度
+                        }
+                    } else {
+                        if (heightDifference > (heightDecor / 4)) {//高度变动超过decor的四分之一则认为是软键盘弹出事件,为什么不用屏幕高度呢?开始以为这样在分屏模式下也可以监听,但是实测不行。
+                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+                                setHeight(heightDecor - heightDifference + barStatusHeight);//这里为什么要添加状态栏高度?
+                            } else {
+                                setHeight(heightDecor - heightDifference);//这里不添加状态栏高度?不懂为什么,原版如此,就先这样吧。遇到再说~
+                            }
+                        } else {
+                            setHeight(FrameLayout.LayoutParams.MATCH_PARENT);//还原默认高度,不能用计算的值,因为虚拟导航栏显示或者隐藏的时候也会改变高度
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    private void setHeight(int height) {
+        if (mFrameLayoutParams.height != height) {//不必要的更新就不要了
+            mFrameLayoutParams.height = height;
+            mContentView.requestLayout();//触发布局更新
+        }
+    }
+
+    private int computeUsableHeight() {
+        Rect r = new Rect();
+        mContentView.getWindowVisibleDisplayFrame(r);
+        // 全屏模式下:直接返回r.bottom,r.top其实是状态栏的高度
+        return (r.bottom - r.top);
+    }
+
+    private int computeUsableWidth() {
+        Rect r = new Rect();
+        mContentView.getWindowVisibleDisplayFrame(r);
+        // 全屏模式下:直接返回r.bottom,r.top其实是状态栏的高度//横屏就是宽度
+        return (r.right - r.left);
+    }
+
+
+    //下面相关代码来自:https://github.com/yy1300326388/AndroidBarUtils/blob/master/app/src/main/java/cn/zsl/androidbarutils/utils/AndroidBarUtils.java
+    //完整代码,全屏时有问题。
+    private static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height";
+    private static final String NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height";
+    private static final String NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width";
+
+    /**
+     * 获取状态栏高度
+     *
+     * @param context context
+     * @return 状态栏高度
+     */
+    private static int getStatusBarHeight(Activity context) {
+        // 获得状态栏高度
+        return getBarHeight(context, STATUS_BAR_HEIGHT_RES_NAME);
+    }
+
+    /**
+     * 获取导航栏高度
+     *
+     * @param activity activity
+     * @return 导航栏高度
+     */
+    private static int getNavigationBarHeight(Activity activity) {
+        if (hasNavBar(activity)) {
+            // 获得导航栏高度
+            return getBarHeight(activity, NAV_BAR_HEIGHT_RES_NAME);
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * 获取横屏状态下导航栏的宽度
+     *
+     * @param activity activity
+     * @return 导航栏的宽度
+     */
+    private static int getNavigationBarWidth(Activity activity) {
+        if (hasNavBar(activity)) {
+            // 获得导航栏高度
+            return getBarHeight(activity, NAV_BAR_WIDTH_RES_NAME);
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * 获取Bar高度
+     *
+     * @param context context
+     * @param barName 名称
+     * @return Bar高度
+     */
+    private static int getBarHeight(Context context, String barName) {
+        // 获得状态栏高度
+        int resourceId = context.getResources().getIdentifier(barName, "dimen", "android");
+        return context.getResources().getDimensionPixelSize(resourceId);
+    }
+
+    /**
+     * 是否有NavigationBar
+     *
+     * @param activity 上下文
+     * @return 是否有NavigationBar
+     */
+    private static boolean hasNavBar(Activity activity) {
+        WindowManager windowManager = activity.getWindowManager();
+        Display d = windowManager.getDefaultDisplay();
+
+        DisplayMetrics realDisplayMetrics = new DisplayMetrics();
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+            d.getRealMetrics(realDisplayMetrics);
+        }
+
+        int realHeight = realDisplayMetrics.heightPixels;
+        int realWidth = realDisplayMetrics.widthPixels;
+
+        DisplayMetrics displayMetrics = new DisplayMetrics();
+        d.getMetrics(displayMetrics);
+
+        int displayHeight = displayMetrics.heightPixels;
+        int displayWidth = displayMetrics.widthPixels;
+
+        return (realWidth - displayWidth) > 0 || (realHeight - displayHeight) > 0;
+    }
+}

+ 7 - 0
app/src/main/java/com/mokasz/libs/ZipExtractorListener.java

@@ -0,0 +1,7 @@
+package com.mokasz.libs;
+
+public abstract class ZipExtractorListener {
+    public abstract void onReady();
+    public abstract void onComplete();
+    public abstract void onProgress(int sofar,int total);
+}

+ 177 - 0
app/src/main/java/com/mokasz/libs/ZipExtractorTask.java

@@ -0,0 +1,177 @@
+package com.mokasz.libs;
+
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+import android.os.AsyncTask;
+import android.util.Log;
+public class ZipExtractorTask extends AsyncTask<Void, Integer, Long> {
+    private final String TAG = "ZipExtractorTask";
+    private final File mInput;
+    private final File mOutput;
+    private int mProgress = 0;
+    private int total = 0;
+    private int sofar = 0;
+    private ZipExtractorListener listener;
+    private boolean mReplaceAll;
+    public ZipExtractorTask(String in, String out,boolean replaceAll,ZipExtractorListener listener){
+        super();
+        mInput = new File(in);
+        mOutput = new File(out);
+        if(!mOutput.exists()){
+            if(!mOutput.mkdirs()){
+                Log.e(TAG, "Failed to make directories:"+mOutput.getAbsolutePath());
+            }
+        }
+        this.listener = listener;
+        mReplaceAll = replaceAll;
+    }
+    @Override
+    protected Long doInBackground(Void... params) {
+        // TODO Auto-generated method stub
+        return unzip();
+    }
+
+    @Override
+    protected void onPostExecute(Long result) {
+        // TODO Auto-generated method stub
+        //super.onPostExecute(result);
+        //解压完成
+        listener.onComplete();
+        if(isCancelled())
+            return;
+    }
+    @Override
+    protected void onPreExecute() {
+        // TODO Auto-generated method stub
+        //super.onPreExecute();
+        //准备解压
+        listener.onReady();
+    }
+    @Override
+    protected void onProgressUpdate(Integer... values) {
+        // TODO Auto-generated method stub
+        //super.onProgressUpdate(values);
+        if(values.length>1){
+            this.total = values[1];
+        }
+        this.sofar = values[0];
+        listener.onProgress(this.sofar,this.total);
+    }
+    private long unzip(){
+        long extractedSize = 0L;
+        Enumeration<ZipEntry> entries;
+        ZipFile zip = null;
+        try {
+            zip = new ZipFile(mInput);
+            long uncompressedSize = getOriginalSize(zip);
+            publishProgress(0, (int) uncompressedSize);
+
+            entries = (Enumeration<ZipEntry>) zip.entries();
+            while(entries.hasMoreElements()){
+                ZipEntry entry = entries.nextElement();
+                if(entry.isDirectory()){
+                    continue;
+                }
+                File destination = new File(mOutput, entry.getName());
+                if(!destination.getParentFile().exists()){
+                    Log.e(TAG, "make="+destination.getParentFile().getAbsolutePath());
+                    destination.getParentFile().mkdirs();
+                }
+                if(destination.exists()&&!mReplaceAll){
+
+                }
+                ProgressReportingOutputStream outStream = new ProgressReportingOutputStream(destination);
+                extractedSize+=copy(zip.getInputStream(entry),outStream);
+                outStream.close();
+            }
+        } catch (ZipException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }finally{
+            try {
+                zip.close();
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+
+        return extractedSize;
+    }
+
+    private long getOriginalSize(ZipFile file){
+        Enumeration<ZipEntry> entries = (Enumeration<ZipEntry>) file.entries();
+        long originalSize = 0l;
+        while(entries.hasMoreElements()){
+            ZipEntry entry = entries.nextElement();
+            if(entry.getSize()>=0){
+                originalSize+=entry.getSize();
+            }
+        }
+        return originalSize;
+    }
+
+    private int copy(InputStream input, OutputStream output){
+        byte[] buffer = new byte[1024*8];
+        BufferedInputStream in = new BufferedInputStream(input, 1024*8);
+        BufferedOutputStream out  = new BufferedOutputStream(output, 1024*8);
+        int count =0,n=0;
+        try {
+            while((n=in.read(buffer, 0, 1024*8))!=-1){
+                out.write(buffer, 0, n);
+                count+=n;
+            }
+            out.flush();
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }finally{
+            try {
+                out.close();
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+            try {
+                in.close();
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+        return count;
+    }
+
+    private final class ProgressReportingOutputStream extends FileOutputStream{
+
+        public ProgressReportingOutputStream(File file)
+                throws FileNotFoundException {
+            super(file);
+            // TODO Auto-generated constructor stub
+        }
+
+        @Override
+        public void write(byte[] buffer, int byteOffset, int byteCount)
+                throws IOException {
+            // TODO Auto-generated method stub
+            super.write(buffer, byteOffset, byteCount);
+            mProgress += byteCount;
+            publishProgress(mProgress);
+        }
+
+    }
+}

+ 305 - 0
app/src/main/java/com/mokasz/libs/utils/FileUtil.java

@@ -0,0 +1,305 @@
+package com.mokasz.libs.utils;
+
+
+import android.os.Environment;
+import android.os.StatFs;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class FileUtil {
+
+    //检查SDCard存在并且可以读写
+    public static boolean isSDCardState(){
+        return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
+    }
+
+    /**
+     * 判断文件是否已经存在
+     *@param filePath 要检查的文件名
+     * @return boolean, true表示存在,false表示不存在
+     */
+    public static boolean isFileExist(String filePath) {
+        File file = new File(filePath);
+        return file.exists();
+    }
+
+    /**
+     * 新建目录
+     * @param path 目录的绝对路径
+     * @return 创建成功则返回true
+     */
+    public static boolean createFolder(String path){
+        File file = new File(path);
+        return file.mkdir();
+    }
+
+    /**
+     * 创建文件
+     *@param path 文件所在目录的目录名
+     * @param fileName 文件名
+     * @return 文件新建成功则返回true
+     */
+    public static boolean createFile(String path, String fileName) {
+        File file = new File(path + File.separator + fileName);
+        if (file.exists()) {
+            return false;
+        } else {
+            try {
+                return file.createNewFile();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 删除单个文件
+     * @param path 文件所在的绝对路径
+     * @param fileName 文件名
+     * @return 删除成功则返回true
+     */
+    public static boolean deleteFile(String path, String fileName) {
+        File file = new File(path + File.separator + fileName);
+        return file.exists() && file.delete();
+    }
+
+    /**
+     * 删除一个目录(可以是非空目录)
+     * @param dir 目录绝对路径
+     */
+    public static boolean deleteDirection(File dir) {
+        if (dir == null || !dir.exists() || dir.isFile()) {
+            return false;
+        }
+        for (File file : dir.listFiles()) {
+            if (file.isFile()) {
+                file.delete();
+            } else if (file.isDirectory()) {
+                deleteDirection(file);//递归
+            }
+        }
+        dir.delete();
+        return true;
+    }
+
+    /**
+     * 将字符串写入文件
+     *@param text  写入的字符串
+     * @param fileStr 文件的绝对路径
+     * @param isAppend true从尾部写入,false从头覆盖写入
+     */
+    public static void writeFile(String text, String fileStr, boolean isAppend) {
+        try {
+            File file = new File(fileStr);
+            File parentFile = file.getParentFile();
+            if (!parentFile.exists()) {
+                parentFile.mkdirs();
+            }
+            if (!file.exists()) {
+                file.createNewFile();
+            }
+            FileOutputStream f = new FileOutputStream(fileStr, isAppend);
+            f.write(text.getBytes());
+            f.close();
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+    public static String readFile(String fileStr){
+        try {
+            StringBuilder sb = new StringBuilder("");
+            File file = new File(fileStr);
+            //打开文件输入流
+            FileInputStream inputStream = new FileInputStream(file);
+            byte[] buffer = new byte[1024];
+            int len = inputStream.read(buffer);
+            //读取文件内容
+            while (len > 0) {
+                sb.append(new String(buffer, 0, len));
+                //继续将数据放到buffer中
+                len = inputStream.read(buffer);
+            }
+            //关闭输入流
+            inputStream.close();
+            return sb.toString();
+        }
+        catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 拷贝文件
+     *@param srcPath 绝对路径
+     * @param destDir 目标文件所在目录
+     * @return boolean true拷贝成功
+     */
+    public static boolean copyFile(String srcPath, String destDir){
+        boolean flag = false;
+        File srcFile = new File(srcPath); // 源文件
+        if (!srcFile.exists()){
+            Log.i("FileUtils is copyFile:","源文件不存在");
+            return false;
+        }
+        // 获取待复制文件的文件名
+        String fileName = srcPath.substring(srcPath.lastIndexOf(File.separator));
+        String destPath = destDir + fileName;
+        if (destPath.equals(srcPath)){
+            Log.i("FileUtils is copyFile:","源文件路径和目标文件路径重复");
+            return false;
+        }
+        File destFile = new File(destPath); // 目标文件
+        if (destFile.exists() && destFile.isFile()){
+            Log.i("FileUtils is copyFile:","该路径下已经有一个同名文件");
+            return false;
+        }
+        File destFileDir = new File(destDir);
+        destFileDir.mkdirs();
+        try{
+            FileInputStream fis = new FileInputStream(srcPath);
+            FileOutputStream fos = new FileOutputStream(destFile);
+            byte[] buf = new byte[1024];
+            int c;
+            while ((c = fis.read(buf)) != -1) {
+                fos.write(buf, 0, c);
+            }
+            fis.close();
+            fos.close();
+            flag = true;
+        }catch (IOException e){
+            e.printStackTrace();
+        }
+        return flag;
+    }
+
+    /**
+     * 重命名文件
+     *@param oldPath 旧文件的绝对路径
+     * @param newPath 新文件的绝对路径
+     * @return 文件重命名成功则返回true
+     */
+    public static boolean renameTo(String oldPath, String newPath){
+        if (oldPath.equals(newPath)){
+            Log.i("FileUtils is renameTo:","文件重命名失败:新旧文件名绝对路径相同");
+            return false;
+        }
+        File oldFile = new File(oldPath);
+        File newFile = new File(newPath);
+
+        return oldFile.renameTo(newFile);
+    }
+
+    /**
+     * 计算某个文件的大小
+     *@param path 文件的绝对路径
+     *@return 文件大小
+     */
+    public static long getFileSize(String path){
+        File file = new File(path);
+        return file.length();
+    }
+
+    /**
+     *计算某个文件夹的大小
+     *@param  file 目录所在绝对路径
+     * @return 文件夹的大小
+     */
+    public static double getDirSize(File file) {
+        if (file.exists()) {
+            //如果是目录则递归计算其内容的总大小
+            if (file.isDirectory()) {
+                File[] children = file.listFiles();
+                double size = 0;
+                for (File f : children)
+                    size += getDirSize(f);
+                return size;
+            } else {//如果是文件则直接返回其大小,以“兆”为单位
+                return (double) file.length() / 1024 / 1024;
+            }
+        } else {
+            return 0.0;
+        }
+    }
+
+    /**
+     * 获取某个路径下的文件列表
+     * @param path 文件路径
+     * @return 文件列表File[] files
+     */
+    public static File[] getFileList(String path) {
+        File file = new File(path);
+        if (file.isDirectory()){
+            File[] files = file.listFiles();
+            if (files != null){
+                return files;
+            }else{
+                return null;
+            }
+        }else{
+            return null;
+        }
+    }
+
+    /**
+     * 计算某个目录包含的文件数量
+     *@param path 目录的绝对路径
+     * @return  文件数量
+     */
+    public static int getFileCount(String path){
+        File directory = new File(path);
+        File[] files = directory.listFiles();
+        return files.length;
+    }
+
+    /**
+     * 获取SDCard 总容量大小(MB)
+     *@param path 目录的绝对路径
+     * @return 总容量大小
+     * */
+    public long getSDCardTotal(String path){
+
+        if(null != path&&path.equals("")){
+
+            StatFs statfs = new StatFs(path);
+            //获取SDCard的Block总数
+            long totalBlocks = statfs.getBlockCount();
+            //获取每个block的大小
+            long blockSize = statfs.getBlockSize();
+            //计算SDCard 总容量大小MB
+            return totalBlocks*blockSize/1024/1024;
+
+        }else{
+            return 0;
+        }
+    }
+
+    /**
+     * 获取SDCard 可用容量大小(MB)
+     *@param path 目录的绝对路径
+     * @return 可用容量大小
+     * */
+    public long getSDCardFree(String path){
+
+        if(null != path&&path.equals("")){
+
+            StatFs statfs = new StatFs(path);
+            //获取SDCard的Block可用数
+            long availaBlocks = statfs.getAvailableBlocks();
+            //获取每个block的大小
+            long blockSize = statfs.getBlockSize();
+            //计算SDCard 可用容量大小MB
+            return availaBlocks*blockSize/1024/1024;
+
+        }else{
+            return 0;
+        }
+    }
+}

+ 49 - 0
app/src/main/java/com/mokasz/libs/utils/GameUtil.java

@@ -0,0 +1,49 @@
+package com.mokasz.libs.utils;
+
+import android.content.Context;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class GameUtil {
+    public static String checkGameVersion(Context context, String version) {
+        final File gameDir = new File(context.getExternalFilesDir(null) + "/game");
+        gameDir.mkdirs();//创建文件夹
+        String versionPath = gameDir.getPath() + "/version";
+        boolean haveVersion = FileUtil.isFileExist(versionPath);
+        int v = 0;
+        String indexPath = gameDir + "/" + "index.html";
+        if (haveVersion) {//如果版本文件存在
+            v = Integer.parseInt(FileUtil.readFile(versionPath));
+        } else {//从安装目录中找
+            StringBuilder sb = new StringBuilder("");
+            try {
+                InputStream inputStream = context.getAssets().open("/version");
+                byte[] buffer = new byte[1024];
+                int len = inputStream.read(buffer);
+                //读取文件内容
+                while (len > 0) {
+                    sb.append(new String(buffer, 0, len));
+                    //继续将数据放到buffer中
+                    len = inputStream.read(buffer);
+                }
+                //关闭输入流
+                inputStream.close();
+                haveVersion = true;
+                v = Integer.parseInt(sb.toString());
+                indexPath = "file:////android_asset/game/index.html";
+            } catch (IOException e) {
+                e.printStackTrace();
+                haveVersion = true;
+            }
+        }
+        if (haveVersion && v >= Integer.parseInt(version) && (indexPath.indexOf("file:////android_asset") == 0 || FileUtil.isFileExist(indexPath))) {
+            //不需要下载压缩包,直接打开
+            return indexPath;
+        }
+        Log.i("qipai", "需要更新");
+        return "";
+    }
+}

+ 103 - 0
app/src/main/java/com/mokasz/libs/utils/GeneralUtil.java

@@ -0,0 +1,103 @@
+package com.mokasz.libs.utils;
+
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+
+import java.io.File;
+
+/**
+ * 通用工具类
+ */
+public class GeneralUtil {
+    /**
+     * 字符串分割
+     *
+     * @param string 字符串
+     * @param symbol 分隔符
+     * @return []
+     */
+    public static String[] splitStr(String string, String symbol) {
+        return string.split(symbol);
+    }
+
+    /**
+     * 打开URL
+     *
+     * @param context 上下文
+     * @param url     URL
+     */
+    public static void openUrl(Context context, String url) {
+        Uri uri = Uri.parse(url);
+        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+        context.startActivity(intent);
+    }
+
+    /**
+     * 拷贝
+     *
+     * @param context 上下文
+     * @param text    拷贝文本
+     */
+    public static void copyText(Context context, String text) {
+        ClipboardManager cm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
+        ClipData mClipData = ClipData.newPlainText("Label", text);
+        cm.setPrimaryClip(mClipData);
+    }
+
+    /**
+     * 获取文件
+     *
+     * @param path     路径
+     * @param fileName 文件名
+     * @return 文件
+     */
+    public static File getFile(String path, String fileName) {
+        return new File(path, fileName);
+    }
+
+    /**
+     * 判断指定文件是否存在
+     *
+     * @param path     路径
+     * @param fileName 文件名
+     * @return boolean
+     */
+    public static boolean isExistFile(String path, String fileName) {
+        try {
+            File file = new File(path, fileName);
+            if (!file.exists()) {
+                return false;
+            }
+        } catch (Exception e) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 获取ApplicationId
+     */
+    public static String getApplicationId(Context context) {
+        return context.getApplicationInfo().processName;
+    }
+
+    /**
+     * 检查版本
+     */
+    public static String getVersionName(Context context) {
+        PackageManager packageManager = context.getPackageManager();
+        String appVersion = null;
+        try {
+            PackageInfo info = packageManager.getPackageInfo(context.getPackageName(), 0);
+            appVersion = info.versionName;
+        } catch (PackageManager.NameNotFoundException e) {
+            e.printStackTrace();
+        }
+        return appVersion;
+    }
+}

+ 81 - 0
app/src/main/java/com/mokasz/libs/utils/OaidHelper.java

@@ -0,0 +1,81 @@
+package com.mokasz.libs.utils;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+
+import com.bun.miitmdid.core.ErrorCode;
+import com.bun.miitmdid.core.MdidSdkHelper;
+import com.bun.miitmdid.interfaces.IIdentifierListener;
+import com.bun.miitmdid.interfaces.IdSupplier;
+
+public class OaidHelper implements IIdentifierListener {
+
+    private AppIdsUpdater _listener;
+
+    public OaidHelper(AppIdsUpdater callback) {
+        _listener = callback;
+
+    }
+
+    public void getDeviceIds(Context cxt) {
+
+        long timeb = System.currentTimeMillis();
+        // 方法调用
+        int nres = CallFromReflect(cxt);
+
+        long timee = System.currentTimeMillis();
+        long offset = timee - timeb;
+        if (nres == ErrorCode.INIT_ERROR_DEVICE_NOSUPPORT) {//不支持的设备
+
+        } else if (nres == ErrorCode.INIT_ERROR_LOAD_CONFIGFILE) {//加载配置文件出错
+
+        } else if (nres == ErrorCode.INIT_ERROR_MANUFACTURER_NOSUPPORT) {//不支持的设备厂商
+
+        } else if (nres == ErrorCode.INIT_ERROR_RESULT_DELAY) {//获取接口是异步的,结果会在回调中返回,回调执行的回调可能在工作线程
+
+        } else if (nres == ErrorCode.INIT_HELPER_CALL_ERROR) {//反射调用出错
+
+        }
+        Log.d(getClass().getSimpleName(), "return value: " + String.valueOf(nres));
+
+    }
+
+    /*
+     * 方法调用
+     *
+     * */
+    private int CallFromReflect(Context cxt) {
+        return MdidSdkHelper.InitSdk(cxt, true, this);
+    }
+
+    /*
+     * 获取相应id
+     *
+     * */
+    @Override
+    public void OnSupport(boolean isSupport, IdSupplier _supplier) {
+        if (_supplier == null) {
+            return;
+        }
+        String oaid = _supplier.getOAID();
+//        String vaid = _supplier.getVAID();
+//        String aaid = _supplier.getAAID();
+//        StringBuilder builder = new StringBuilder();
+//        builder.append("support: ").append(isSupport ? "true" : "false").append("\n");
+//        builder.append("OAID: ").append(oaid).append("\n");
+//        builder.append("VAID: ").append(vaid).append("\n");
+//        builder.append("AAID: ").append(aaid).append("\n");
+//        String idstext = builder.toString();
+        String idstext = oaid;
+        if (_listener != null) {
+            _listener.OnIdsAvalid(idstext);
+        }
+    }
+
+    public interface AppIdsUpdater {
+        void OnIdsAvalid(@NonNull String ids);
+    }
+
+}

+ 121 - 0
app/src/main/java/com/mokasz/libs/utils/OkhttpUtil.java

@@ -0,0 +1,121 @@
+package com.mokasz.libs.utils;
+
+
+import android.os.Message;
+
+import com.mokasz.libs.MOKActivity;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.concurrent.TimeUnit;
+
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
+public class OkhttpUtil {
+    private static OkhttpUtil mInstance;
+    private OkHttpClient mOkHttpClient;
+    public static final int DOWNLOAD_FAIL = 0;
+    public static final int DOWNLOAD_PROGRESS = 1;
+    public static final int DOWNLOAD_SUCCESS = 2;
+
+    /**
+     * 单例加静态对象
+     */
+    public static OkhttpUtil getInstance() {
+        if (mInstance == null) {
+            synchronized (OkhttpUtil.class) {
+                if (mInstance == null) {
+                    mInstance = new OkhttpUtil();
+                }
+            }
+        }
+        return mInstance;
+    }
+
+    /**
+     * OkHttp的一些参数配置
+     */
+    private OkhttpUtil() {
+        mOkHttpClient = new OkHttpClient.Builder()
+                .readTimeout(15, TimeUnit.SECONDS)
+                .connectTimeout(20, TimeUnit.SECONDS)
+                .writeTimeout(20, TimeUnit.SECONDS)
+                .build();
+    }
+
+    /**
+     * 下载文件并保存
+     */
+    public void download(final MOKActivity ctx, final String remoteZIP, final String extension, final String version) {
+        final File gameDir = ctx.getExternalFilesDir(null);
+        File file = new File(gameDir, "game." + extension);
+        if (file.exists()) {
+            file.delete();
+        }
+        Request request = new Request.Builder().url(remoteZIP).build();
+        mOkHttpClient.newCall(request).enqueue(new Callback() {
+            @Override
+            public void onFailure(Call call, IOException e) {
+                Message message = Message.obtain();
+                message.what = DOWNLOAD_FAIL;
+                ctx.downLoadHandler.sendMessage(message);
+            }
+
+            @Override
+            public void onResponse(Call call, Response response) throws IOException {
+                InputStream is = null;
+                byte[] buf = new byte[2048];
+                int len = 0;
+                FileOutputStream fos = null;
+                try {
+                    is = response.body().byteStream();
+                    long total = response.body().contentLength();
+                    fos = new FileOutputStream(file);
+                    long sum = 0;
+                    while ((len = is.read(buf)) != -1) {
+                        fos.write(buf, 0, len);
+                        sum += len;
+                        int progress = (int) (sum * 1.0f / total * 100);
+                        //下载中
+                        Message message = Message.obtain();
+                        message.what = DOWNLOAD_PROGRESS;
+                        message.obj = progress;
+                        ctx.downLoadHandler.sendMessage(message);
+
+                    }
+                    fos.flush();
+                    //下载完成
+                    Message message = Message.obtain();
+                    message.what = DOWNLOAD_SUCCESS;
+                    message.obj = file.getAbsolutePath() + "|" + extension + "|" + version;
+                    ctx.downLoadHandler.sendMessage(message);
+                } catch (Exception e) {
+                    Message message = Message.obtain();
+                    message.what = DOWNLOAD_FAIL;
+                    ctx.downLoadHandler.sendMessage(message);
+                } finally {
+                    try {
+                        if (is != null)
+                            is.close();
+                    } catch (IOException e) {
+
+                    }
+                    try {
+                        if (fos != null) {
+                            fos.close();
+                        }
+                    } catch (IOException e) {
+
+                    }
+                }
+            }
+        });
+    }
+}
+

+ 206 - 0
app/src/main/java/com/mokasz/libs/utils/SystemUtil.java

@@ -0,0 +1,206 @@
+package com.mokasz.libs.utils;
+
+
+import android.Manifest;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Build;
+import android.provider.Settings;
+import android.support.v4.app.ActivityCompat;
+import android.telephony.TelephonyManager;
+import android.view.View;
+
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
+
+/**
+ * 获取手机信息工具
+ */
+public class SystemUtil {
+
+    /**
+     * 获取IMEI
+     */
+    public static String getIMEI(Context context) {
+        String result = "";
+        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+        if (telephonyManager != null) {
+            //版本小于8
+            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
+                if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
+                    result = telephonyManager.getDeviceId();
+                }
+            } else {
+                if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
+                    result = telephonyManager.getImei();
+                }
+            }
+        }
+        return result == null ? "" : result;
+    }
+
+    /**
+     * 获取AndroidID
+     */
+    public static String getAndroidID(Context context) {
+        String result = "";
+        result = Settings.System.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
+        return result == null ? "" : result;
+    }
+
+    /**
+     * 获取MAC地址
+     */
+    public static String getMac(Context context) {
+        String result = null;
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+            result = getLocalMacAddressFromWifiInfo(context);
+        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            result = getMac();
+        }
+        String[] str = result.split(",");
+        if (str.length > 0) {
+            result = str[0];
+        }
+        return result == null ? "" : result;
+    }
+
+    /**
+     * wifi信息获取本地mac
+     */
+    private static String getLocalMacAddressFromWifiInfo(Context context) {
+        WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        WifiInfo winfo = wifi.getConnectionInfo();
+        String result = winfo.getMacAddress();
+        return result == null ? "" : result;
+    }
+
+    /**
+     * mac地址
+     */
+    public static String getMac() {
+        String macSerial = null;
+        String str = "";
+        String result = "";
+        try {
+            Process pp = Runtime.getRuntime().exec("ip addr");
+            InputStreamReader ir = new InputStreamReader(pp.getInputStream());
+            LineNumberReader input = new LineNumberReader(ir);
+            for (; null != str; ) {
+                str = input.readLine();
+                if (str != null) {
+                    macSerial = str.trim();// 去空格
+                    if (macSerial.indexOf("link/ether") != -1) {
+                        if (macSerial.split(" ").length >= 2) {
+                            if (result.equals("")) {
+                                result = macSerial.split(" ")[1];
+                            } else {
+                                result = result.concat(",").concat(macSerial.split(" ")[1]);
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (IOException ex) {
+        }
+        return result == null ? "" : result;
+    }
+
+    /**
+     * 程序是否在前台
+     *
+     * @return
+     */
+    public static boolean isOnForeground(Context context) {
+        ActivityManager activityManager = (ActivityManager) context.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
+        String packageName = context.getApplicationContext().getPackageName();
+        List<ActivityManager.RunningAppProcessInfo> appProcessInfos = activityManager.getRunningAppProcesses();
+        if (appProcessInfos == null) {
+            return false;
+        }
+        for (ActivityManager.RunningAppProcessInfo appProcess : appProcessInfos) {
+            if (appProcess.processName.equals(packageName)
+                    && appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 权限检查
+     *
+     * @param context         上下文
+     * @param permissionsList 权限列表
+     * @return 未获得权限列表
+     */
+    public static List<String> hasPermission(Context context, List<String> permissionsList) {
+        List<String> temp = new ArrayList<>();
+        if (permissionsList.size() != 0) {
+            for (int i = 0; i < permissionsList.size(); i++) {
+                if (!SystemUtil.hasPermission(context, permissionsList.get(i))) {
+                    temp.add(permissionsList.get(i));
+                }
+            }
+        }
+        return temp;
+    }
+
+    /**
+     * 单权限检查
+     *
+     * @param context    上下文
+     * @param permission 权限
+     * @return boolean
+     */
+    public static boolean hasPermission(Context context, String permission) {
+        return PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(context, WRITE_EXTERNAL_STORAGE);
+    }
+
+    /**
+     * 申请权限
+     *
+     * @param activity        activity
+     * @param permissionsList 权限列表
+     */
+    public static void requestPermission(Activity activity, List<String> permissionsList, int requestCode) {
+        List<String> list = hasPermission(activity, permissionsList);
+        if (list.size() != 0) {
+            String[] arr = new String[list.size()];
+            list.toArray(arr);
+            ActivityCompat.requestPermissions(activity, arr, requestCode);
+        }
+    }
+
+    /**
+     * 隐藏底部导航栏
+     * TIP:常用于Activity中覆写的onWindowFocusChanged方法
+     *
+     * @param activity 需要隐藏的Activity
+     */
+    public static void hideBottomUIMenu(Activity activity) {
+        View decorView = activity.getWindow().getDecorView();
+        int uiFlags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
+                | View.SYSTEM_UI_FLAG_FULLSCREEN; // hide status bar
+        if (android.os.Build.VERSION.SDK_INT >= 19) {
+            uiFlags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+        } else {
+            uiFlags |= View.SYSTEM_UI_FLAG_LOW_PROFILE;
+        }
+        decorView.setSystemUiVisibility(uiFlags);
+        activity.getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(arg0 -> hideBottomUIMenu(activity));//处理bar弹出生成后无法隐藏
+    }
+}

+ 19 - 0
app/src/main/java/com/mokasz/libs/utils/ToastUtil.java

@@ -0,0 +1,19 @@
+package com.mokasz.libs.utils;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.widget.Toast;
+
+public class ToastUtil {
+    private static Toast toast;
+
+    @SuppressLint("ShowToast")
+    public static void showToast(Context context, String msg) {
+        if (toast == null) {
+            toast = Toast.makeText(context, msg, Toast.LENGTH_SHORT);
+        } else {
+            toast.setText(msg);
+        }
+        toast.show();
+    }
+}

+ 91 - 0
app/src/main/java/com/mokasz/libs/utils/WechatUtil.java

@@ -0,0 +1,91 @@
+package com.mokasz.libs.utils;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+
+import com.aries.jjdz.mz.BuildConfig;
+import com.aries.jjdz.mz.R;
+import com.tencent.mm.opensdk.constants.ConstantsAPI;
+import com.tencent.mm.opensdk.modelbiz.WXLaunchMiniProgram;
+import com.tencent.mm.opensdk.modelmsg.SendAuth;
+import com.tencent.mm.opensdk.modelmsg.SendMessageToWX;
+import com.tencent.mm.opensdk.modelmsg.WXMediaMessage;
+import com.tencent.mm.opensdk.modelmsg.WXWebpageObject;
+import com.tencent.mm.opensdk.openapi.IWXAPI;
+import com.tencent.mm.opensdk.openapi.WXAPIFactory;
+
+/**
+ * 微信工具
+ */
+public class WechatUtil {
+    public static final String APP_ID = BuildConfig.WX_APP_ID;
+    public static IWXAPI api;
+
+    /**
+     * 将应用注册到微信
+     */
+    public static void regToWX(Context context) {
+        api = WXAPIFactory.createWXAPI(context, APP_ID, true);
+        api.registerApp(APP_ID);
+        context.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                api.registerApp(APP_ID);
+            }
+        }, new IntentFilter(ConstantsAPI.ACTION_REFRESH_WXAPP));
+    }
+
+    /**
+     * 微信登录
+     */
+    public static void wxLogin(Context context) {
+        if (!api.isWXAppInstalled()) {
+            ToastUtil.showToast(context, "您还未安装微信!");
+            return;
+        }
+        SendAuth.Req req = new SendAuth.Req();
+        req.scope = "snsapi_userinfo";
+        req.state = "diandi_wx_login";
+        api.sendReq(req);
+    }
+
+    /**
+     * 分享到微信
+     * flag 0:分享到好友
+     * flag 1:分享到朋友圈
+     */
+    public static void shareLinkToWX(final int flag, Context context, String url, String title, String descroption) {
+        if (!api.isWXAppInstalled()) {
+            ToastUtil.showToast(context, "您还未安装微信!");
+            return;
+        }
+        WXWebpageObject webPage = new WXWebpageObject();
+        webPage.webpageUrl = url;
+        WXMediaMessage msg = new WXMediaMessage(webPage);
+        msg.title = title;
+        msg.description = descroption;
+        Bitmap bitmao = BitmapFactory.decodeResource(context.getResources(), R.drawable.share_icon);
+        msg.setThumbImage(bitmao);
+        SendMessageToWX.Req req = new SendMessageToWX.Req();
+        req.transaction = String.valueOf(System.currentTimeMillis());
+        req.message = msg;
+        req.scene = flag == 0 ? SendMessageToWX.Req.WXSceneSession : SendMessageToWX.Req.WXSceneTimeline;
+        api.sendReq(req);
+    }
+
+    /**
+     * 打开微信小程序
+     */
+    public static void openWXApplets(Context context, String userName, String appletsPath) {
+        IWXAPI api = WXAPIFactory.createWXAPI(context, BuildConfig.WX_APP_ID, true);
+        WXLaunchMiniProgram.Req req = new WXLaunchMiniProgram.Req();
+        req.userName = userName; // 填小程序原始id
+        req.path = appletsPath;                  ////拉起小程序页面的可带参路径,不填默认拉起小程序首页,对于小游戏,可以只传入 query 部分,来实现传参效果,如:传入 "?foo=bar"。
+        req.miniprogramType = WXLaunchMiniProgram.Req.MINIPTOGRAM_TYPE_RELEASE;// 可选打开 开发版,体验版和正式版
+        api.sendReq(req);
+    }
+}

+ 22 - 0
app/src/main/java/com/mokasz/receiver/InstallReceiver.java

@@ -0,0 +1,22 @@
+package com.mokasz.receiver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class InstallReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
+
+        }
+
+        if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+
+        }
+
+        if (Intent.ACTION_PACKAGE_REPLACED.equals(intent.getAction())) {
+
+        }
+    }
+}

+ 29 - 0
app/src/main/java/com/mokasz/utils/BroadcastUtil.java

@@ -0,0 +1,29 @@
+package com.mokasz.utils;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import com.mokasz.receiver.InstallReceiver;
+
+/**
+ * 动态注册广播工具类
+ * TIP:相对应的广播接收处理类在receiver包下
+ */
+public class BroadcastUtil {
+
+    /**
+     * 注册软件的安装/卸载/覆盖
+     * TIPS:Android8之后需要动态注册
+     *
+     * @param context 上下文
+     */
+    private static void registerInstallBroadcast(Context context) {
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        intentFilter.addDataScheme("package");
+        context.registerReceiver(new InstallReceiver(), intentFilter);
+    }
+}

BIN
app/src/main/res/drawable/ad_close.png


BIN
app/src/main/res/drawable/ad_logo.png


BIN
app/src/main/res/drawable/chapin.png


BIN
app/src/main/res/drawable/logo.png


BIN
app/src/main/res/drawable/ren.png


BIN
app/src/main/res/drawable/share_icon.png


BIN
app/src/main/res/drawable/splash.jpg


+ 80 - 0
app/src/main/res/layout/activity_main.xml

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@drawable/splash"
+    android:gravity="bottom"
+    android:paddingLeft="0dp"
+    android:paddingTop="0dp"
+    android:paddingRight="0dp"
+    android:paddingBottom="0dp"
+    tools:context=".MainActivity">
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+
+            <ImageView
+                android:id="@+id/imageView4"
+                android:layout_width="307dp"
+                android:layout_height="158dp"
+                android:layout_gravity="center"
+                android:layout_marginBottom="150dp"
+                android:src="@drawable/logo" />
+
+            <android.support.constraint.ConstraintLayout
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+            </android.support.constraint.ConstraintLayout>
+
+        </FrameLayout>
+
+        <ImageView
+            android:id="@+id/imageView5"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:scaleType="fitEnd"
+            android:src="@drawable/ren" />
+
+
+        <RelativeLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+
+            <TextView
+                android:id="@+id/textView"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentBottom="true"
+                android:layout_centerHorizontal="true"
+                android:layout_marginBottom="20dp"
+                android:text="首次启动加载较慢,请耐心等候..." />
+        </RelativeLayout>
+    </RelativeLayout>
+
+    <LinearLayout
+        android:id="@+id/webview_container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <WebView
+            android:id="@+id/webview"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+    </LinearLayout>
+
+    <FrameLayout
+        android:id="@+id/banner_container"
+        android:layout_alignParentBottom="true"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"></FrameLayout>
+</RelativeLayout>

+ 13 - 0
app/src/main/res/layout/banner_ad.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:id="@+id/banner_container"
+        android:layout_width="match_parent"
+        android:layout_height="150dp"
+        android:layout_alignParentBottom="true"
+        android:orientation="horizontal" />
+</RelativeLayout>

+ 17 - 0
app/src/main/res/layout/native_ad.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright © 2018-2020 TopOn. All rights reserved.
+  ~ https://www.toponad.com
+  ~ Licensed under the TopOn SDK License Agreement
+  ~ https://github.com/toponteam/TopOn-Android-SDK/blob/master/LICENSE
+  -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <RelativeLayout
+        android:id="@+id/container"
+        android:layout_width="match_parent"
+        android:layout_height="300dp"
+        android:layout_alignParentBottom="true" />
+</RelativeLayout>

+ 142 - 0
app/src/main/res/layout/native_ad_item.xml

@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright © 2018-2020 TopOn. All rights reserved.
+  ~ https://www.toponad.com
+  ~ Licensed under the TopOn SDK License Agreement
+  ~ https://github.com/toponteam/TopOn-Android-SDK/blob/master/LICENSE
+  -->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="#ffffff"
+    android:orientation="vertical">
+
+
+    <!--<TextView-->
+    <!--android:id="@+id/native_ad_install_btn"-->
+    <!--android:layout_width="wrap_content"-->
+    <!--android:layout_height="wrap_content"-->
+    <!--android:layout_alignEnd="@+id/native_ad_content_image_area"-->
+    <!--android:layout_alignRight="@+id/native_ad_content_image_area"-->
+    <!--android:layout_below="@+id/native_ad_title"-->
+    <!--android:background="#888888"-->
+    <!--android:paddingBottom="5dp"-->
+    <!--android:paddingLeft="15dp"-->
+    <!--android:paddingRight="15dp"-->
+    <!--android:paddingTop="5dp"-->
+    <!--android:textColor="@android:color/white"-->
+    <!--android:textSize="11dp"-->
+    <!--android:visibility="gone"/>-->
+
+
+    <FrameLayout
+        android:id="@+id/native_ad_image"
+        android:layout_width="45dp"
+        android:layout_height="45dp"
+        android:layout_alignParentBottom="true"
+        android:layout_marginTop="10dp"
+        android:layout_marginRight="10dp"
+        android:scaleType="fitCenter"></FrameLayout>
+
+
+    <TextView
+        android:id="@+id/native_ad_install_btn"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignTop="@id/native_ad_image"
+        android:layout_alignBottom="@id/native_ad_image"
+        android:layout_alignParentRight="true"
+        android:layout_marginLeft="10dp"
+        android:background="#2095F1"
+        android:gravity="center"
+        android:paddingLeft="20dp"
+        android:paddingRight="20dp"
+        android:textColor="#ffffff" />
+
+    <TextView
+        android:id="@+id/native_ad_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignTop="@id/native_ad_image"
+        android:layout_toLeftOf="@id/native_ad_install_btn"
+        android:layout_toRightOf="@id/native_ad_image"
+        android:ellipsize="end"
+        android:maxLines="1"
+        android:textColor="#000000"
+        android:textSize="15dp"
+        android:textStyle="bold" />
+
+    <TextView
+        android:id="@+id/native_ad_desc"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignBottom="@id/native_ad_image"
+        android:layout_toLeftOf="@id/native_ad_install_btn"
+        android:layout_toRightOf="@id/native_ad_image"
+        android:ellipsize="end"
+        android:maxLines="1"
+        android:textColor="#777777"
+        android:textSize="12dp" />
+
+    <LinearLayout
+        android:id="@+id/native_ad_version_area"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_above="@id/native_ad_image"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@+id/native_ad_version"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:autoLink="all"
+            android:ellipsize="end"
+            android:includeFontPadding="false"
+            android:maxLines="1"
+            android:padding="4dp"
+            android:text="Version"
+            android:textColor="#000000"
+            android:textSize="15dp"
+            android:textStyle="bold" />
+    </LinearLayout>
+
+
+    <FrameLayout
+        android:id="@+id/native_ad_content_image_area"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_above="@id/native_ad_version_area"></FrameLayout>
+
+    <com.anythink.nativead.api.ATNativeImageView
+        android:id="@+id/native_ad_logo"
+        android:layout_width="40dp"
+        android:layout_height="20dp"
+        android:layout_alignParentRight="true"
+        android:layout_marginTop="2dp"
+        android:layout_marginRight="2dp"
+        android:visibility="gone" />
+
+
+    <ImageView
+        android:id="@+id/native_self_adlogo"
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:layout_marginLeft="2dp"
+        android:src="@drawable/ad_logo" />
+
+    <TextView
+        android:id="@+id/native_ad_from"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignTop="@id/native_ad_logo"
+        android:layout_marginLeft="2dp"
+        android:layout_marginRight="2dp"
+        android:layout_toLeftOf="@id/native_self_adlogo"
+        android:background="#888888"
+        android:gravity="center"
+        android:paddingLeft="2dp"
+        android:paddingRight="2dp"
+        android:textColor="#ffffff"
+        android:textSize="6dp" />
+
+</RelativeLayout>

+ 15 - 0
app/src/main/res/layout/splash.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <ImageView
+        android:id="@+id/splashImage"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:scaleType="fitXY"
+        android:src="@drawable/splash"/>
+</RelativeLayout>

+ 20 - 0
app/src/main/res/layout/splash_ad.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#ffffff">
+
+    <ImageView
+        android:id="@+id/splashImage"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:scaleType="fitXY"
+        android:src="@drawable/splash"/>
+    <FrameLayout
+        android:id="@+id/splash_content"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+</RelativeLayout>

BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png


+ 10 - 0
app/src/main/res/values/colors.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="purple_200">#FFBB86FC</color>
+    <color name="purple_500">#FF6200EE</color>
+    <color name="purple_700">#FF3700B3</color>
+    <color name="teal_200">#FF03DAC5</color>
+    <color name="teal_700">#FF018786</color>
+    <color name="black">#FF000000</color>
+    <color name="white">#FFFFFFFF</color>
+</resources>

+ 3 - 0
app/src/main/res/values/strings.xml

@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">将军顶住</string>
+</resources>

+ 9 - 0
app/src/main/res/values/style.xml

@@ -0,0 +1,9 @@
+<resources>
+
+    <style name="wxTheme" parent="Theme.AppCompat.Light.NoActionBar">
+        <item name="android:windowFullscreen">true</item>
+        <item name="android:windowIsTranslucent">false</item>
+        <item name="android:windowDisablePreview">true</item>
+    </style>
+
+</resources>

+ 17 - 0
app/src/main/res/xml/anythink_bk_gdt_file_path.xml

@@ -0,0 +1,17 @@
+<!--
+  ~ Copyright © 2018-2020 TopOn. All rights reserved.
+  ~ https://www.toponad.com
+  ~ Licensed under the TopOn SDK License Agreement
+  ~ https://github.com/toponteam/TopOn-Android-SDK/blob/master/LICENSE
+  -->
+
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+    <external-path name="gdt_sdk_download_path" path="GDTDOWNLOAD" />
+    <root-path name="root" path="" />
+    <external-cache-path
+        name="gdt_sdk_download_path1"
+        path="com_qq_e_download" />
+    <cache-path
+        name="gdt_sdk_download_path2"
+        path="com_qq_e_download" />
+</paths>

+ 14 - 0
app/src/main/res/xml/anythink_bk_sigmob_file_path.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright © 2018-2020 TopOn. All rights reserved.
+  ~ https://www.toponad.com
+  ~ Licensed under the TopOn SDK License Agreement
+  ~ https://github.com/toponteam/TopOn-Android-SDK/blob/master/LICENSE
+  -->
+
+<paths>
+    <!-- 这个下载路径不可以修改,SigDownload -->
+    <external-cache-path name="SigMob_root" path="SigDownload" />
+    <external-path name="SigMob_root_external" path="." />
+    <root-path name="SigMob_root" path="." />
+</paths>

+ 16 - 0
app/src/main/res/xml/anythink_bk_tt_file_path.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright © 2018-2020 TopOn. All rights reserved.
+  ~ https://www.toponad.com
+  ~ Licensed under the TopOn SDK License Agreement
+  ~ https://github.com/toponteam/TopOn-Android-SDK/blob/master/LICENSE
+  -->
+
+<paths>
+    <external-path name="tt_external_root" path="." />
+    <external-path name="tt_external_download" path="Download" />
+    <external-files-path name="tt_external_files_download" path="Download" />
+    <files-path name="tt_internal_file_download" path="Download" />
+    <cache-path name="tt_internal_cache_download" path="Download" />
+    <root-path name="root" path="" />
+</paths>

+ 4 - 0
app/src/main/res/xml/file_path.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+    <root-path name="root_path" path="."/>
+</paths>

+ 27 - 0
build.gradle

@@ -0,0 +1,27 @@
+buildscript {
+    repositories {
+        google()
+        jcenter()
+        mavenCentral()
+    }
+    dependencies {
+        classpath "com.android.tools.build:gradle:4.1.2"
+        classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.10'
+
+        // NOTE: Do not place your application dependencies here; they belong
+        // in the individual module build.gradle files
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        mavenCentral()
+        jcenter() // Warning: this repository is going to shut down soon
+        maven { url "https://jitpack.io" } // 添加jitpac
+    }
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}

BIN
gradle/wrapper/gradle-wrapper.jar


+ 6 - 0
gradle/wrapper/gradle-wrapper.properties

@@ -0,0 +1,6 @@
+#Wed Jun 23 15:12:37 CST 2021
+distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME

+ 172 - 0
gradlew

@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"

+ 84 - 0
gradlew.bat

@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega

+ 2 - 0
settings.gradle

@@ -0,0 +1,2 @@
+rootProject.name = "TD_JJ"
+include ':app'