Repository: Bzaigege/GameSDKFrameDemo Branch: master Commit: 31e812349bfd Files: 424 Total size: 50.5 MB Directory structure: gitextract_qbthkmxs/ ├── .gitignore ├── GameSDKBuildJarTool/ │ ├── .gitignore │ ├── build.gradle │ ├── libs/ │ │ ├── common-24.3.0.jar │ │ ├── guava-18.0.jar │ │ ├── manifest-merger-24.3.0.jar │ │ ├── proguard.jar │ │ ├── retrace.jar │ │ └── sdk-common-25.1.2.jar │ ├── src/ │ │ └── main/ │ │ ├── cmd/ │ │ │ └── test/ │ │ │ ├── jar/ │ │ │ │ ├── test.jar │ │ │ │ └── test_proguard.jar │ │ │ ├── java/ │ │ │ │ ├── HelloWorld.java │ │ │ │ └── TestA.java │ │ │ └── proguard/ │ │ │ ├── proguard_config.pro │ │ │ └── tools/ │ │ │ ├── proguard.jar │ │ │ └── rt.jar │ │ ├── java/ │ │ │ └── com/ │ │ │ └── bzai/ │ │ │ └── gamesdk/ │ │ │ └── build/ │ │ │ ├── BuildJarTask.java │ │ │ ├── Config.java │ │ │ ├── Main.java │ │ │ ├── bean/ │ │ │ │ ├── ErrorMsg.java │ │ │ │ └── Project.java │ │ │ ├── tools/ │ │ │ │ ├── JavaTool.java │ │ │ │ ├── ProGuardTool.java │ │ │ │ ├── ServerTool.java │ │ │ │ └── exec/ │ │ │ │ └── Shell.java │ │ │ └── utils/ │ │ │ ├── FileUtils.java │ │ │ └── Utils.java │ │ └── resources/ │ │ ├── config │ │ ├── proguard_config.pro │ │ └── project_list │ └── 必读说明 ├── GameSDKDemo_Release/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── bzai/ │ │ └── gamesdkframe/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── bzai/ │ │ │ └── gamesdkframe/ │ │ │ └── demo/ │ │ │ ├── GameApplication.java │ │ │ └── GameSDKMain.java │ │ └── res/ │ │ ├── layout/ │ │ │ └── activity_main.xml │ │ └── values/ │ │ ├── colors.xml │ │ └── strings.xml │ └── test/ │ └── java/ │ └── com/ │ └── bzai/ │ └── gamesdkframe/ │ └── ExampleUnitTest.java ├── GameSDKLibrary_Release/ │ ├── .gitignore │ ├── build.gradle │ ├── libs/ │ │ ├── alipaySdk-20180601.jar │ │ ├── android-support-v4.jar │ │ ├── org.apache.http.legacy.jar │ │ ├── sdk_test_v1.0.0.jar │ │ └── wechat-sdk-android-without-mta-5.1.4.jar │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── suyutech/ │ │ └── baselibrary/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── assets/ │ │ │ ├── Channel_config.txt │ │ │ ├── Plugin_config.txt │ │ │ ├── Project_config.txt │ │ │ └── SDKInfo.json │ │ └── res/ │ │ └── values/ │ │ └── strings.xml │ └── test/ │ └── java/ │ └── com/ │ └── suyutech/ │ └── baselibrary/ │ └── ExampleUnitTest.java ├── GameSDK_API/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── bzai/ │ │ └── gamesdk/ │ │ └── api/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ └── java/ │ │ └── com/ │ │ └── bzai/ │ │ └── gamesdk/ │ │ ├── GameInfoSetting.java │ │ ├── SDKApplication.java │ │ ├── api/ │ │ │ └── SDKAPI.java │ │ ├── bean/ │ │ │ ├── info/ │ │ │ │ ├── AccountEventResultInfo.java │ │ │ │ └── PlayerInfo.java │ │ │ └── params/ │ │ │ ├── GameRoleParams.java │ │ │ └── PayParams.java │ │ └── listener/ │ │ ├── AccountCallBackLister.java │ │ ├── ExitCallBackLister.java │ │ ├── InitCallBackLister.java │ │ └── PurchaseCallBackListener.java │ └── test/ │ └── java/ │ └── com/ │ └── bzai/ │ └── gamesdk/ │ └── api/ │ └── ExampleUnitTest.java ├── GameSDK_BeginProject/ │ ├── GameSDK_Project_Custom/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── bzai/ │ │ │ └── gamesdk/ │ │ │ └── project/ │ │ │ └── channel/ │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── assets/ │ │ │ │ ├── Plugin_config.txt │ │ │ │ ├── Project_config.txt │ │ │ │ └── SDKInfo.json │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── bzai/ │ │ │ └── gamesdk/ │ │ │ └── project/ │ │ │ ├── CustomProject.java │ │ │ └── ProjectApplication.java │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── bzai/ │ │ └── gamesdk/ │ │ └── project/ │ │ └── channel/ │ │ └── ExampleUnitTest.java │ └── GameSDK_Project_JuHe/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── bzai/ │ │ └── gamesdk/ │ │ └── project/ │ │ └── juhe/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── assets/ │ │ │ ├── Plugin_config.txt │ │ │ ├── Project_config.txt │ │ │ └── SDKInfo.json │ │ └── java/ │ │ └── com/ │ │ └── bzai/ │ │ └── gamesdk/ │ │ └── project/ │ │ ├── JuHeProject.java │ │ └── ProjectApplication.java │ └── test/ │ └── java/ │ └── com/ │ └── bzai/ │ └── gamesdk/ │ └── project/ │ └── juhe/ │ └── ExampleUnitTest.java ├── GameSDK_Channel/ │ ├── GameSDK_Channel_Lexiang/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── libs/ │ │ │ ├── HeepayPlugin_v3.0.jar │ │ │ ├── eventbus-3.0.0.jar │ │ │ └── youxunsdk.jar │ │ ├── proguard-rules.pro │ │ ├── src/ │ │ │ ├── androidTest/ │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── bzai/ │ │ │ │ └── gamesdk/ │ │ │ │ └── channel/ │ │ │ │ └── test/ │ │ │ │ └── ExampleInstrumentedTest.java │ │ │ ├── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── assets/ │ │ │ │ │ └── Channel_config.txt │ │ │ │ ├── java/ │ │ │ │ │ └── com/ │ │ │ │ │ └── bzai/ │ │ │ │ │ └── gamesdk/ │ │ │ │ │ └── channel/ │ │ │ │ │ ├── application/ │ │ │ │ │ │ └── ChannelApplication.java │ │ │ │ │ └── lexiang/ │ │ │ │ │ └── LexiangSDK.java │ │ │ │ └── res/ │ │ │ │ ├── drawable/ │ │ │ │ │ ├── youxun_border_stroke.xml │ │ │ │ │ ├── youxun_cir_hint_bg.xml │ │ │ │ │ ├── youxun_cir_rect.xml │ │ │ │ │ ├── youxun_drawable_1.xml │ │ │ │ │ ├── youxun_drawable_2.xml │ │ │ │ │ ├── youxun_drawable_3.xml │ │ │ │ │ ├── youxun_drawable_33.xml │ │ │ │ │ ├── youxun_drawable_4.xml │ │ │ │ │ ├── youxun_drawable_44.xml │ │ │ │ │ ├── youxun_drawable_5.xml │ │ │ │ │ ├── youxun_drawable_6.xml │ │ │ │ │ └── youxun_service_rect.xml │ │ │ │ └── layout/ │ │ │ │ ├── youxun_account.xml │ │ │ │ ├── youxun_account_hint.xml │ │ │ │ ├── youxun_account_login.xml │ │ │ │ ├── youxun_account_reg.xml │ │ │ │ ├── youxun_bound.xml │ │ │ │ ├── youxun_dialog.xml │ │ │ │ ├── youxun_dialog2.xml │ │ │ │ ├── youxun_dialog3.xml │ │ │ │ ├── youxun_floating.xml │ │ │ │ ├── youxun_gb_dialog.xml │ │ │ │ ├── youxun_gb_item.xml │ │ │ │ ├── youxun_gb_menu.xml │ │ │ │ ├── youxun_gift_bag.xml │ │ │ │ ├── youxun_login.xml │ │ │ │ ├── youxun_login_footprint.xml │ │ │ │ ├── youxun_login_menu.xml │ │ │ │ ├── youxun_login_option_item.xml │ │ │ │ ├── youxun_login_popup.xml │ │ │ │ ├── youxun_menu_2.xml │ │ │ │ ├── youxun_menu_3.xml │ │ │ │ ├── youxun_menu_4.xml │ │ │ │ ├── youxun_mobile.xml │ │ │ │ ├── youxun_mobile_login.xml │ │ │ │ ├── youxun_mobile_reg.xml │ │ │ │ ├── youxun_mobile_verify.xml │ │ │ │ ├── youxun_notice.xml │ │ │ │ ├── youxun_pay.xml │ │ │ │ ├── youxun_toast.xml │ │ │ │ └── youxun_webview.xml │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── bzai/ │ │ │ └── gamesdk/ │ │ │ └── channel/ │ │ │ └── test/ │ │ │ └── ExampleUnitTest.java │ │ └── 开发者说明 │ └── GameSDK_Channel_Test/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ ├── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── bzai/ │ │ │ └── gamesdk/ │ │ │ └── channel/ │ │ │ └── test/ │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── assets/ │ │ │ │ └── Channel_config.txt │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── bzai/ │ │ │ │ └── gamesdk/ │ │ │ │ └── channel/ │ │ │ │ ├── application/ │ │ │ │ │ └── ChannelApplication.java │ │ │ │ └── test/ │ │ │ │ └── TestChannelSDK.java │ │ │ └── res/ │ │ │ └── values/ │ │ │ └── strings.xml │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── bzai/ │ │ └── gamesdk/ │ │ └── channel/ │ │ └── test/ │ │ └── ExampleUnitTest.java │ └── 开发者说明 ├── GameSDK_Manager/ │ ├── GameSDK_Module_Account/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── bzai/ │ │ │ └── gamesdk/ │ │ │ └── module/ │ │ │ └── account/ │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── bzai/ │ │ │ └── gamesdk/ │ │ │ └── module/ │ │ │ └── account/ │ │ │ ├── AccountManager.java │ │ │ └── bean/ │ │ │ ├── AccountBean.java │ │ │ └── AccountCallBackBean.java │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── bzai/ │ │ └── gamesdk/ │ │ └── module/ │ │ └── account/ │ │ └── ExampleUnitTest.java │ ├── GameSDK_Module_Init/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── bzai/ │ │ │ └── gamesdk/ │ │ │ └── module/ │ │ │ └── init/ │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main/ │ │ │ ├── AndroidManifest.xml │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── bzai/ │ │ │ └── gamesdk/ │ │ │ └── module/ │ │ │ └── init/ │ │ │ └── InitManager.java │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── bzai/ │ │ └── gamesdk/ │ │ └── module/ │ │ └── init/ │ │ └── ExampleUnitTest.java │ └── GameSDK_Module_Purchase/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── bzai/ │ │ └── gamesdk/ │ │ └── module/ │ │ └── purchase/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── bzai/ │ │ │ └── gamesdk/ │ │ │ └── module/ │ │ │ └── purchase/ │ │ │ ├── PurchaseManager.java │ │ │ └── PurchaseResult.java │ │ └── res/ │ │ └── values/ │ │ └── strings.xml │ └── test/ │ └── java/ │ └── com/ │ └── bzai/ │ └── gamesdk/ │ └── module/ │ └── purchase/ │ └── ExampleUnitTest.java ├── GameSDK_Manager_Impl/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── bzai/ │ │ └── gamesdk/ │ │ └── manager/ │ │ └── impl/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── bzai/ │ │ │ └── gamesdk/ │ │ │ └── invoke/ │ │ │ └── plugin/ │ │ │ ├── AlipayPluginApi.java │ │ │ └── WechatPluginApi.java │ │ └── res/ │ │ └── values/ │ │ └── strings.xml │ └── test/ │ └── java/ │ └── com/ │ └── bzai/ │ └── gamesdk/ │ └── manager/ │ └── impl/ │ └── ExampleUnitTest.java ├── GameSDK_Plugin/ │ ├── GameSDK_Plugin_Alipay/ │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── libs/ │ │ │ └── alipaySdk-20180601.jar │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── bzai/ │ │ │ └── gamesdk/ │ │ │ └── plugin/ │ │ │ └── alipay/ │ │ │ └── ExampleInstrumentedTest.java │ │ ├── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── bzai/ │ │ │ │ └── gamesdk/ │ │ │ │ └── plugin/ │ │ │ │ └── alipay/ │ │ │ │ ├── AlipayPlugin.java │ │ │ │ └── pay/ │ │ │ │ ├── AlipayPay.java │ │ │ │ └── PayResult.java │ │ │ └── res/ │ │ │ └── values/ │ │ │ └── strings.xml │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── bzai/ │ │ └── gamesdk/ │ │ └── plugin/ │ │ └── alipay/ │ │ └── ExampleUnitTest.java │ └── GameSDK_Plugin_Wechat/ │ ├── .gitignore │ ├── build.gradle │ ├── libs/ │ │ └── wechat-sdk-android-without-mta-5.1.4.jar │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── bzai/ │ │ └── gamesdk/ │ │ └── plugin/ │ │ └── wechat/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ └── java/ │ │ └── com/ │ │ └── bzai/ │ │ └── gamesdk/ │ │ └── plugin/ │ │ └── wechat/ │ │ ├── WechatPlugin.java │ │ ├── login/ │ │ │ └── WechatLogin.java │ │ └── pay/ │ │ └── WechatPay.java │ └── test/ │ └── java/ │ └── com/ │ └── bzai/ │ └── gamesdk/ │ └── plugin/ │ └── wechat/ │ └── ExampleUnitTest.java ├── GameSDK_Utils/ │ ├── .gitignore │ ├── build.gradle │ ├── libs/ │ │ ├── android-support-v4.jar │ │ └── org.apache.http.legacy.jar │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── bzai/ │ │ └── gamesdk/ │ │ └── utils/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ └── java/ │ │ └── com/ │ │ └── bzai/ │ │ └── gamesdk/ │ │ └── common/ │ │ ├── utils_base/ │ │ │ ├── cache/ │ │ │ │ └── ApplicationCache.java │ │ │ ├── config/ │ │ │ │ ├── ErrCode.java │ │ │ │ └── TypeConfig.java │ │ │ ├── frame/ │ │ │ │ ├── google/ │ │ │ │ │ ├── gson/ │ │ │ │ │ │ ├── DefaultDateTypeAdapter.java │ │ │ │ │ │ ├── ExclusionStrategy.java │ │ │ │ │ │ ├── FieldAttributes.java │ │ │ │ │ │ ├── FieldNamingPolicy.java │ │ │ │ │ │ ├── FieldNamingStrategy.java │ │ │ │ │ │ ├── Gson.java │ │ │ │ │ │ ├── GsonBuilder.java │ │ │ │ │ │ ├── InstanceCreator.java │ │ │ │ │ │ ├── JsonArray.java │ │ │ │ │ │ ├── JsonDeserializationContext.java │ │ │ │ │ │ ├── JsonDeserializer.java │ │ │ │ │ │ ├── JsonElement.java │ │ │ │ │ │ ├── JsonIOException.java │ │ │ │ │ │ ├── JsonNull.java │ │ │ │ │ │ ├── JsonObject.java │ │ │ │ │ │ ├── JsonParseException.java │ │ │ │ │ │ ├── JsonParser.java │ │ │ │ │ │ ├── JsonPrimitive.java │ │ │ │ │ │ ├── JsonSerializationContext.java │ │ │ │ │ │ ├── JsonSerializer.java │ │ │ │ │ │ ├── JsonStreamParser.java │ │ │ │ │ │ ├── JsonSyntaxException.java │ │ │ │ │ │ ├── LongSerializationPolicy.java │ │ │ │ │ │ ├── TreeTypeAdapter.java │ │ │ │ │ │ ├── TypeAdapter.java │ │ │ │ │ │ ├── TypeAdapterFactory.java │ │ │ │ │ │ ├── annotations/ │ │ │ │ │ │ │ ├── Expose.java │ │ │ │ │ │ │ ├── SerializedName.java │ │ │ │ │ │ │ ├── Since.java │ │ │ │ │ │ │ ├── Until.java │ │ │ │ │ │ │ └── package-info.java │ │ │ │ │ │ ├── internal/ │ │ │ │ │ │ │ ├── $Gson$Preconditions.java │ │ │ │ │ │ │ ├── $Gson$Types.java │ │ │ │ │ │ │ ├── ConstructorConstructor.java │ │ │ │ │ │ │ ├── Excluder.java │ │ │ │ │ │ │ ├── JsonReaderInternalAccess.java │ │ │ │ │ │ │ ├── LazilyParsedNumber.java │ │ │ │ │ │ │ ├── ObjectConstructor.java │ │ │ │ │ │ │ ├── Primitives.java │ │ │ │ │ │ │ ├── Streams.java │ │ │ │ │ │ │ ├── StringMap.java │ │ │ │ │ │ │ ├── UnsafeAllocator.java │ │ │ │ │ │ │ ├── bind/ │ │ │ │ │ │ │ │ ├── ArrayTypeAdapter.java │ │ │ │ │ │ │ │ ├── CollectionTypeAdapterFactory.java │ │ │ │ │ │ │ │ ├── DateTypeAdapter.java │ │ │ │ │ │ │ │ ├── JsonTreeReader.java │ │ │ │ │ │ │ │ ├── JsonTreeWriter.java │ │ │ │ │ │ │ │ ├── MapTypeAdapterFactory.java │ │ │ │ │ │ │ │ ├── ObjectTypeAdapter.java │ │ │ │ │ │ │ │ ├── ReflectiveTypeAdapterFactory.java │ │ │ │ │ │ │ │ ├── SqlDateTypeAdapter.java │ │ │ │ │ │ │ │ ├── TimeTypeAdapter.java │ │ │ │ │ │ │ │ ├── TypeAdapterRuntimeTypeWrapper.java │ │ │ │ │ │ │ │ └── TypeAdapters.java │ │ │ │ │ │ │ └── package-info.java │ │ │ │ │ │ ├── package-info.java │ │ │ │ │ │ ├── reflect/ │ │ │ │ │ │ │ ├── TypeToken.java │ │ │ │ │ │ │ └── package-info.java │ │ │ │ │ │ └── stream/ │ │ │ │ │ │ ├── JsonReader.java │ │ │ │ │ │ ├── JsonScope.java │ │ │ │ │ │ ├── JsonToken.java │ │ │ │ │ │ ├── JsonWriter.java │ │ │ │ │ │ ├── MalformedJsonException.java │ │ │ │ │ │ └── StringPool.java │ │ │ │ │ └── volley/ │ │ │ │ │ ├── AuthFailureError.java │ │ │ │ │ ├── Cache.java │ │ │ │ │ ├── CacheDispatcher.java │ │ │ │ │ ├── DefaultRetryPolicy.java │ │ │ │ │ ├── ExecutorDelivery.java │ │ │ │ │ ├── InternalUtils.java │ │ │ │ │ ├── Network.java │ │ │ │ │ ├── NetworkDispatcher.java │ │ │ │ │ ├── NetworkError.java │ │ │ │ │ ├── NetworkResponse.java │ │ │ │ │ ├── NoConnectionError.java │ │ │ │ │ ├── ParseError.java │ │ │ │ │ ├── RedirectError.java │ │ │ │ │ ├── Request.java │ │ │ │ │ ├── RequestQueue.java │ │ │ │ │ ├── Response.java │ │ │ │ │ ├── ResponseDelivery.java │ │ │ │ │ ├── RetryPolicy.java │ │ │ │ │ ├── ServerError.java │ │ │ │ │ ├── TimeoutError.java │ │ │ │ │ ├── VolleyError.java │ │ │ │ │ ├── VolleyLog.java │ │ │ │ │ └── toolbox/ │ │ │ │ │ ├── AndroidAuthenticator.java │ │ │ │ │ ├── Authenticator.java │ │ │ │ │ ├── BasicNetwork.java │ │ │ │ │ ├── ByteArrayPool.java │ │ │ │ │ ├── ClearCacheRequest.java │ │ │ │ │ ├── DiskBasedCache.java │ │ │ │ │ ├── HttpClientStack.java │ │ │ │ │ ├── HttpHeaderParser.java │ │ │ │ │ ├── HttpStack.java │ │ │ │ │ ├── HurlStack.java │ │ │ │ │ ├── ImageLoader.java │ │ │ │ │ ├── ImageRequest.java │ │ │ │ │ ├── JsonArrayRequest.java │ │ │ │ │ ├── JsonObjectRequest.java │ │ │ │ │ ├── JsonRequest.java │ │ │ │ │ ├── NetworkImageView.java │ │ │ │ │ ├── NoCache.java │ │ │ │ │ ├── PoolingByteArrayOutputStream.java │ │ │ │ │ ├── RequestFuture.java │ │ │ │ │ ├── StringRequest.java │ │ │ │ │ └── Volley.java │ │ │ │ ├── logger/ │ │ │ │ │ ├── AndroidLogAdapter.java │ │ │ │ │ ├── CsvFormatStrategy.java │ │ │ │ │ ├── DiskLogAdapter.java │ │ │ │ │ ├── DiskLogStrategy.java │ │ │ │ │ ├── FormatStrategy.java │ │ │ │ │ ├── LogAdapter.java │ │ │ │ │ ├── LogStrategy.java │ │ │ │ │ ├── LogcatLogStrategy.java │ │ │ │ │ ├── Logger.java │ │ │ │ │ ├── LoggerPrinter.java │ │ │ │ │ ├── PrettyFormatStrategy.java │ │ │ │ │ ├── Printer.java │ │ │ │ │ └── Utils.java │ │ │ │ └── walle/ │ │ │ │ ├── WalleChannelReader.java │ │ │ │ └── payload_reader/ │ │ │ │ ├── ApkUtil.java │ │ │ │ ├── ChannelInfo.java │ │ │ │ ├── ChannelReader.java │ │ │ │ ├── Pair.java │ │ │ │ ├── PayloadReader.java │ │ │ │ └── SignatureNotFoundException.java │ │ │ ├── interfaces/ │ │ │ │ ├── CallBackListener.java │ │ │ │ └── LifeCycleInterface.java │ │ │ ├── net/ │ │ │ │ ├── RequestExecutor.java │ │ │ │ ├── base/ │ │ │ │ │ ├── VolleyRequestWrapper.java │ │ │ │ │ ├── VolleyResponseListener.java │ │ │ │ │ └── VolleySingleton.java │ │ │ │ ├── impl/ │ │ │ │ │ ├── BaseRequest.java │ │ │ │ │ ├── BaseRequestCallback.java │ │ │ │ │ ├── BaseRequestUtils.java │ │ │ │ │ └── bean/ │ │ │ │ │ └── ResponseResult.java │ │ │ │ └── request/ │ │ │ │ ├── IRequestManager.java │ │ │ │ ├── RequestCallback.java │ │ │ │ └── VolleyRequestManager.java │ │ │ ├── parse/ │ │ │ │ ├── channel/ │ │ │ │ │ ├── Channel.java │ │ │ │ │ ├── ChannelBeanList.java │ │ │ │ │ ├── ChannelListenerImpl.java │ │ │ │ │ └── ChannelManager.java │ │ │ │ ├── plugin/ │ │ │ │ │ ├── Plugin.java │ │ │ │ │ ├── PluginBeanList.java │ │ │ │ │ ├── PluginManager.java │ │ │ │ │ └── PluginReflectApi.java │ │ │ │ └── project/ │ │ │ │ ├── Project.java │ │ │ │ ├── ProjectBeanList.java │ │ │ │ └── ProjectManager.java │ │ │ ├── proguard/ │ │ │ │ ├── ProguardInterface.java │ │ │ │ └── ProguardObject.java │ │ │ └── utils/ │ │ │ ├── ArrayUtils.java │ │ │ ├── CodeUtils.java │ │ │ ├── ContextUtils.java │ │ │ ├── CryptUtils.java │ │ │ ├── DateUtils.java │ │ │ ├── FileUtils.java │ │ │ ├── IOUtils.java │ │ │ ├── JsonUtils.java │ │ │ ├── ListUtils.java │ │ │ ├── LogUtils.java │ │ │ ├── Md5Utils.java │ │ │ ├── ObjectUtils.java │ │ │ └── StringUtils.java │ │ ├── utils_business/ │ │ │ ├── cache/ │ │ │ │ ├── BaseCache.java │ │ │ │ ├── SDKInfoCache.java │ │ │ │ └── SharePreferencesCache.java │ │ │ └── config/ │ │ │ ├── KeyConfig.java │ │ │ └── UrlConfig.java │ │ └── utils_ui/ │ │ ├── BitmapUtils.java │ │ ├── LoadingUtils.java │ │ ├── ResourseIdUtils.java │ │ ├── ToastUtils.java │ │ └── activity/ │ │ └── SplashActivity.java │ └── test/ │ └── java/ │ └── com/ │ └── bzai/ │ └── gamesdk/ │ └── utils/ │ └── ExampleUnitTest.java ├── README.md ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── bzai/ │ │ └── gamesdkframe/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── bzai/ │ │ │ └── gamesdkframe/ │ │ │ ├── GameApplication.java │ │ │ └── GameSDKMain.java │ │ └── res/ │ │ ├── layout/ │ │ │ └── activity_main.xml │ │ └── values/ │ │ ├── colors.xml │ │ └── strings.xml │ └── test/ │ └── java/ │ └── com/ │ └── bzai/ │ └── gamesdkframe/ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── 框架必读说明 ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.iml .gradle /local.properties /.idea/workspace.xml /.idea/libraries .DS_Store /build /captures .externalNativeBuild ================================================ FILE: GameSDKBuildJarTool/.gitignore ================================================ /build ================================================ FILE: GameSDKBuildJarTool/build.gradle ================================================ apply plugin: 'java-library' apply plugin: 'idea' dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile files('libs/proguard.jar') } //解决控件台中文乱码问题 tasks.withType(JavaCompile) { options.encoding = "UTF-8" } tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn tasks.findByName('idea') } sourceSets { main { resources { srcDirs "src/main/resources" } } } sourceCompatibility = "1.7" targetCompatibility = "1.7" ================================================ FILE: GameSDKBuildJarTool/src/main/cmd/test/java/HelloWorld.java ================================================ package com.bzai.demo; public class HelloWorld { public static void main(String[] args){ System.out.println("hello world"); test(); } public static void test(){ TestA testA = new TestA(); testA.Test(); } } ================================================ FILE: GameSDKBuildJarTool/src/main/cmd/test/java/TestA.java ================================================ package com.bzai.demo; public class TestA { public String name = "asdfa"; public void Test(){ System.out.println("name:"+name); } } ================================================ FILE: GameSDKBuildJarTool/src/main/cmd/test/proguard/proguard_config.pro ================================================ -dontskipnonpubliclibraryclassmembers -dontshrink -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*,!code/allocation/variable -dontusemixedcaseclassnames -keepattributes SourceFile,LineNumberTable,*Annotation*,Signature,Deprecated,InnerClasses -keepparameternames -renamesourcefileattribute SourceFile -verbose -dontwarn android.support.v4.** # Keep names - Native method names. Keep all native class/method names. -keepclasseswithmembers,allowshrinking class * { native ; } ================================================ FILE: GameSDKBuildJarTool/src/main/cmd/test/proguard/tools/rt.jar ================================================ [File too large to display: 49.4 MB] ================================================ FILE: GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/BuildJarTask.java ================================================ package com.bzai.gamesdk.build; import com.android.manifmerger.ManifestMerger2; import com.android.manifmerger.MergingReport; import com.android.manifmerger.XmlDocument; import com.android.utils.StdLogger; import com.bzai.gamesdk.build.bean.ErrorMsg; import com.bzai.gamesdk.build.bean.Project; import com.bzai.gamesdk.build.tools.JavaTool; import com.bzai.gamesdk.build.tools.ProGuardTool; import com.bzai.gamesdk.build.tools.ServerTool; import com.bzai.gamesdk.build.utils.FileUtils; import com.bzai.gamesdk.build.utils.Utils; import java.io.File; import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.StandardOpenOption; import java.util.List; /** * 混淆jarTask */ public class BuildJarTask implements Runnable{ @Override public void run() { //创建输出路径 String outputPath; try { Config.getInstance().loadConfig(); outputPath = Config.getInstance().getOutPutPath(); FileUtils.createDirectories(outputPath,true); }catch (Exception e){ e.printStackTrace(); return; } //同步资源 List projectList; try { projectList = Config.getInstance().getProject(); if (null == projectList || projectList.isEmpty()){ System.out.println("project list is empty"); return; } String workspacePath = outputPath + File.separator + "workspace"; FileUtils.createDirectory(workspacePath); ServerTool.DownServerResource(projectList,workspacePath); }catch (Exception e){ e.printStackTrace(); return; } //buildJar String jarName = Config.getInstance().getJarName(); String jarVersion = Config.getInstance().getJarVersion(); String buildJar = jarName + "_" + jarVersion; String jarOutputPath = outputPath + File.separator + "jar_out"; String jarFileOutputPath = jarOutputPath + File.separator + buildJar + ".jar"; ErrorMsg errorMsg = buildJar(projectList, jarFileOutputPath); if (errorMsg.code != Utils.OK){ System.out.println("Tips:" + errorMsg.getMessage() + "\n"); errorMsg.e.printStackTrace(); return; } //build resource file. String resourceOutputPath = outputPath + File.separator + "resource"; try{ FileUtils.createDirectory(resourceOutputPath); buildResourceFile(resourceOutputPath, projectList); }catch (Exception e){ e.printStackTrace(); return; } System.out.println("\n"); System.out.println("SDK输出路径:" + jarFileOutputPath); System.out.println("资源文件输出路径:" + resourceOutputPath); } /** * 编译生成混淆jar包过程 * @param projectList 工程配置 * @param jarOutputPath jar包输出路径 * @return */ private ErrorMsg buildJar(List projectList, String jarOutputPath){ File jarFile = new File(jarOutputPath); String outputPath = jarFile.getParent(); //创建一个Temp工程 Project tmpBuildProject = new Project(); String projectName = "tmpBuildProject"; String tmpBuildProjectPath = outputPath + File.separator + projectName; tmpBuildProject.setName(projectName); tmpBuildProject.setPath(tmpBuildProjectPath); //创建temp工程目录,Java 和 libs String projectSrcPath = tmpBuildProjectPath + File.separator + Project.JAVA_RELATIVE_PATH; try{ FileUtils.createDirectoriesIfNonExists(outputPath); FileUtils.createDirectoriesIfNonExists(tmpBuildProjectPath); FileUtils.createDirectoriesIfNonExists(projectSrcPath); }catch (Exception e){ return new ErrorMsg(Utils.ERROR, e.getMessage(), e); } //将各个项目的java文件下的源文件拷贝到 tmpBuildProject 的src文件下。 try{ for (Project project : projectList){ String tmpProjectSrcPath = project.getPath() + File.separator + Project.JAVA_RELATIVE_PATH; if (FileUtils.exists(tmpProjectSrcPath)){ FileUtils.copy(tmpProjectSrcPath, projectSrcPath, false); } } }catch (Exception e){ return new ErrorMsg(Utils.ERROR, e.getMessage(), e); } // .java and .jar compile to .class String classPath = getClasspath(tmpBuildProject,projectList); String classFilesOutputPath = tmpBuildProjectPath + File.separator + "classes"; try { FileUtils.createDirectory(classFilesOutputPath); JavaTool.compile(projectSrcPath, classPath, classFilesOutputPath, null); }catch (Exception e){ return new ErrorMsg(Utils.ERROR, "构建SDK-编译.java to .class出错", e); } // .class compile to .jar String noProguardJar = outputPath + File.separator + "no_proguard.jar"; try{ JavaTool.classFilesToJar(classFilesOutputPath, noProguardJar, null); }catch (Exception e){ return new ErrorMsg(Utils.ERROR, "构建SDK-编译.class打包jar出错", e); } //proguard jar try{ String mapping = outputPath + File.separator + "proguard_mapping.txt"; String logging = outputPath + File.separator + "proguard_log.txt"; String root_path = System.getProperty("user.dir"); String proJarPath = root_path + File.separator + "GameSDKBuildJarTool" + File.separator + "libs" + File.separator + "proguard.jar"; String proguardConfigFilePath = Config.getInstance().get_config_file_path("proguard_config.pro"); ProGuardTool.run(proJarPath, noProguardJar, classPath, proguardConfigFilePath, mapping, logging, jarOutputPath); }catch (Exception e){ return new ErrorMsg(Utils.ERROR, "构建SDK-混淆jar出错", e); } return new ErrorMsg(Utils.OK, "ok"); } /** * 合并工程资源文件过程 * @param resourceOutputPath * @param projectList * @throws IOException * @throws InterruptedException * @throws ManifestMerger2.MergeFailureException */ public void buildResourceFile(String resourceOutputPath, List projectList) throws IOException, InterruptedException, ManifestMerger2.MergeFailureException { /*copy libs,assets,res to library project*/ String libsPath = resourceOutputPath + File.separator + Project.LIBS_FILE; String assetsPath = resourceOutputPath + File.separator + Project.ASSETS_FILE; final String resPath = resourceOutputPath + File.separator + Project.RES_FILE; String jniLibsFilePath = resourceOutputPath + File.separator + Project.JNI_LIBS_FILE; for (Project project : projectList){ /*copy assets*/ String projectAssetsPath = project.getPath() + File.separator + Project.ASSETS_RELATIVE_PATH; if (FileUtils.exists(projectAssetsPath)){ FileUtils.createDirectoryIfNonExists(assetsPath); FileUtils.copy(projectAssetsPath, assetsPath, false); } /*copy jni libs*/ String projectJniLibsPath = project.getPath() + File.separator + Project.JNI_LIBS_RELATIVE_PATH; if (FileUtils.exists(projectJniLibsPath)){ FileUtils.createDirectoryIfNonExists(jniLibsFilePath); FileUtils.copy(projectJniLibsPath, jniLibsFilePath, false); } /*copy libs*/ String projectLibsPath = project.getPath() + File.separator + Project.LIBS_RELATIVE_PATH; if (FileUtils.exists(projectLibsPath)){ FileUtils.createDirectoryIfNonExists(libsPath); FileUtils.copy(projectLibsPath, libsPath, false); } /*copy res*/ final String projectResPath = project.getPath() + File.separator + Project.RES_RELATIVE_PATH; if (FileUtils.exists(projectResPath)){ FileUtils.createDirectoryIfNonExists(resPath); FileUtils.copy(projectResPath, resPath, false); } //manifest merge String projectManifestPath = project.getPath() + File.separator + Project.ANDROID_MANIFEST_RELATIVE_PATH; String mainManifestPath = resourceOutputPath + File.separator + Project.ANDROID_MANIFEST_FILE; if (!FileUtils.exists(mainManifestPath)){ FileUtils.copy(projectManifestPath, mainManifestPath, true); }else{ StdLogger stdLogger = new StdLogger(StdLogger.Level.ERROR); ManifestMerger2.Invoker manifestMerger = ManifestMerger2.newMerger(new File(mainManifestPath), stdLogger, ManifestMerger2.MergeType.APPLICATION); manifestMerger.addLibraryManifest(new File(projectManifestPath)); manifestMerger.withFeatures(ManifestMerger2.Invoker.Feature.REMOVE_TOOLS_DECLARATIONS); MergingReport mergingReport = manifestMerger.merge(); XmlDocument xmlDocument = mergingReport.getMergedDocument().get(); Files.write(FileSystems.getDefault().getPath(mainManifestPath), xmlDocument.prettyPrint().getBytes("UTF-8"), StandardOpenOption.WRITE); switch (mergingReport.getResult()) { case WARNING: // fall through since these are just warnings. mergingReport.log(stdLogger); break; case SUCCESS: break; case ERROR: mergingReport.log(stdLogger); throw new RuntimeException(mergingReport.getReportString()); default: throw new RuntimeException("Unhandled result type : " + mergingReport.getResult()); } } } // /*如果jar文件中存在assets资源文件,需要jar中的将assets文件提取出来*/ // List jarFileList = FileUtils.getFileList(libsPath, ".jar"); // for (String jarFilePath : jarFileList){ // File jarFile = new File(jarFilePath); // String unzipToFilePath = libsPath +File.separator // + jarFile.getName().substring(0, jarFile.getName().lastIndexOf(".")); // Utils.jarFileUnzip(jarFilePath, unzipToFilePath); // String assetsFilePath = unzipToFilePath + File.separator + Project.ASSETS_FILE; // if (FileUtils.exists(assetsFilePath)){ // String outputPathAssetsPath = resourceOutputPath + File.separator + Project.ASSETS_FILE; // FileUtils.createDirectoryIfNonExists(outputPathAssetsPath); // FileUtils.move(assetsFilePath, outputPathAssetsPath, false); // // /*删除原来的jar,重新压缩一个删除assets的jar文件*/ // FileUtils.delete(jarFilePath); // JavaTool.classFilesToJar(unzipToFilePath, jarFilePath, null); // // FileUtils.delete(unzipToFilePath); // }else{ // FileUtils.delete(unzipToFilePath); // } // } } private String getClasspath(Project project, List projectList){ String classpath = ""; //获取工程jar路径 for (Project dependProject : projectList){ String projectPath = dependProject.getPath(); String projectLibsPath = projectPath + File.separator + Project.LIBS_RELATIVE_PATH; if (FileUtils.exists(projectLibsPath)){ String jarPathSet = Utils.getJarPathSet(projectLibsPath,Utils.OS_SEMICOLON); if (!Utils.isEmpty(jarPathSet)){ if (!Utils.isEmpty(classpath)){ classpath = classpath + Utils.OS_SEMICOLON; } classpath = classpath + jarPathSet; } } } //获取工程源码路径 String projectJavaPath = project.getPath() + File.separator + Project.JAVA_RELATIVE_PATH; if (FileUtils.exists(projectJavaPath)){ if (!Utils.isEmpty(classpath)){ classpath = classpath + Utils.OS_SEMICOLON; } classpath = classpath + projectJavaPath; } //获取SDK版本 android.jar 路径 if (!Utils.isEmpty(classpath)){ classpath = classpath + Utils.OS_SEMICOLON; } classpath = classpath + getMinSdkVersionPath(); return classpath; } /** * 获取Android sdk jar的存放路径 * * @return */ private String getMinSdkVersionPath(){ String androidSDKPath = Config.getInstance().getAndroidSdkPath(); String androidJarPath = androidSDKPath + File.separator +"platforms" + File.separator+ Config.getInstance().getTargetSdkVersion()+File.separator+"android.jar"; return androidJarPath; } } ================================================ FILE: GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/Config.java ================================================ package com.bzai.gamesdk.build; import com.bzai.gamesdk.build.bean.Project; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.Set; /** * 配置文件 */ public class Config { /** * android SDK 路径 */ public String androidSdkPath; /** * android target 版本 */ public String targetSdkVersion; /** * 输出jar包的名称 */ public String jarName; /** * 输出jar包的版本号 */ public String jarVersion; /** * 输出jar的路径 */ public String outPutPath; private static Config mConfig; private static byte[] syncObj = new byte[0]; private Config(){ } public static Config getInstance(){ if (null == mConfig){ synchronized (syncObj){ if (null == mConfig){ mConfig = new Config(); } } } return mConfig; } /** * 加载配置文件 */ public void loadConfig() throws IOException{ //这段代码在IDEA中可以正常读取到 // Properties properties = new Properties(); // URL url = ClassLoader.getSystemClassLoader().getResource("config"); // properties.load(new FileInputStream(url.getFile())); String config_path = get_config_file_path("config"); Properties properties = new Properties(); properties.load(new FileInputStream(config_path)); androidSdkPath = properties.getProperty("androidSdkPath"); targetSdkVersion = properties.getProperty("targetSdkVersion"); jarName = properties.getProperty("jarName"); jarVersion = properties.getProperty("jarVersion"); outPutPath = properties.getProperty("outPutPath"); } /** * 解析配置文件的工程配置 * @return * @throws IOException */ public List getProject() throws IOException{ // Properties properties = new Properties(); // URL url = ClassLoader.getSystemClassLoader().getResource("project_list"); // properties.load(new FileInputStream(url.getFile())); String config_path = get_config_file_path("project_list"); Properties properties = new Properties(); properties.load(new FileInputStream(config_path)); List projectList = new ArrayList<>(); Set keySet = properties.keySet(); for (Object key : keySet){ String keyStr = (String) key; String value = properties.getProperty(keyStr); value = value.replaceAll(" ",""); String[] valueList = value.split(","); int revision = 0; if (valueList[0].matches("[0-9]*")){ revision = Integer.parseInt(valueList[0]); } Project project = new Project(); project.setVersion(revision); project.setName(keyStr); project.setUrl(valueList[1]); projectList.add(project); } return projectList; } public String get_config_file_path(String file_name){ //在AndroidStudio中用绝对路径读取 //但是要在Run/Debug configurations 配置Working directory工作目录路径 String root_path = System.getProperty("user.dir"); String file_path = root_path + File.separator + "GameSDKBuildJarTool" + File.separator + "src" + File.separator + "main" + File.separator + "resources" + File.separator + file_name; // System.out.println(file_path); return file_path; } public String getAndroidSdkPath() { return androidSdkPath; } public void setAndroidSdkPath(String androidSdkPath) { this.androidSdkPath = androidSdkPath; } public String getTargetSdkVersion() { return targetSdkVersion; } public void setTargetSdkVersion(String targetSdkVersion) { this.targetSdkVersion = targetSdkVersion; } public String getJarName() { return jarName; } public void setJarName(String jarName) { this.jarName = jarName; } public String getJarVersion() { return jarVersion; } public void setJarVersion(String jarVersion) { this.jarVersion = jarVersion; } public String getOutPutPath() { return outPutPath; } public void setOutPutPath(String outPutPath) { this.outPutPath = outPutPath; } } ================================================ FILE: GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/Main.java ================================================ package com.bzai.gamesdk.build; public class Main { public static void main(String[] args){ new Thread(new BuildJarTask()).start(); } } ================================================ FILE: GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/bean/ErrorMsg.java ================================================ package com.bzai.gamesdk.build.bean; /** * 描述打包结果 */ public class ErrorMsg { public int code; public String message; public Exception e; public ErrorMsg(int code, String message){ this.code = code; this.message = message; } public ErrorMsg(int code, String message, Exception e){ this.code = code; this.message = message; this.e = e; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } ================================================ FILE: GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/bean/Project.java ================================================ package com.bzai.gamesdk.build.bean; import java.io.File; /** * Project 配置类 */ public class Project { /** * 源码相对于项目所在路径。 */ public static final String JAVA_RELATIVE_PATH = "src" + File.separator + "main" + File.separator + "java"; /** * res资源文件相对于项目所在路径。 */ public static final String RES_RELATIVE_PATH = "src" + File.separator + "main" + File.separator + "res"; /** * assets文件相对于项目所在路径。 */ public static final String ASSETS_RELATIVE_PATH = "src" + File.separator + "main" + File.separator + "assets"; /** * libs相对于项目所在路径。 */ public static final String LIBS_RELATIVE_PATH = "libs"; /** * Android manifest相对于项目所在路径。 */ public static final String ANDROID_MANIFEST_RELATIVE_PATH = "src" + File.separator + "main" + File.separator + "AndroidManifest.xml"; /** * jni libs相对于项目所在路径。 */ public static final String JNI_LIBS_RELATIVE_PATH = "src" + File.separator + "main" + File.separator + "jniLibs"; /** * jni libs相对于项目所在路径。 */ public static final String MAIN_FILE_RELATIVE_PATH = "src" + File.separator + "main"; /** * unknown文件相对于项目所在路径。 */ public static final String UNKNOWN_FILE_RELATIVE_PATH = "src" + File.separator + "main" + File.separator + "unknown"; /** * project src file name. */ public static final String SRC_FILE = "src"; /** * project assets file name. */ public static final String ASSETS_FILE = "assets"; /** * project res file name. */ public static final String RES_FILE = "res"; /** * project libs file name. */ public static final String LIBS_FILE = "libs"; /** * project libs file name. */ public static final String JNI_LIBS_FILE = "jniLibs"; /** * project unknown file name. */ public static final String UNKNOWN_FILE = "unknown"; /** * app file name. */ public static final String APP_FILE = "app"; /** * project android manifest file name. */ public static final String ANDROID_MANIFEST_FILE = "AndroidManifest.xml"; /** * 项目名称 */ public String name; /** * 打包路径 */ public String path; /** * 服务器版本 */ public int version; /** * 服务器地址 */ public String url; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public int getVersion() { return version; } public void setVersion(int version) { this.version = version; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } } ================================================ FILE: GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/tools/JavaTool.java ================================================ package com.bzai.gamesdk.build.tools; import com.bzai.gamesdk.build.tools.exec.Shell; import com.bzai.gamesdk.build.utils.Utils; import javax.tools.JavaCompiler; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import java.io.FileWriter; import java.io.IOException; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class JavaTool { public static void compile(String sourceCodePath, String classPath, String classFileOutputPath, String logOutputPath) throws Exception{ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); Path source = FileSystems.getDefault().getPath(sourceCodePath); final List javaFilePathList = new ArrayList<>(); Files.walkFileTree(source, new SimpleFileVisitor(){ @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (file.toString().endsWith(".java")){ javaFilePathList.add(file.toAbsolutePath().toString()); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { return FileVisitResult.CONTINUE; } }); //编译日志输出到文件 FileWriter fileWriter = null; StandardJavaFileManager standardJavaFileManager = null; boolean compileSucceed = true; try { if (!Utils.isEmpty(logOutputPath)){ fileWriter = new FileWriter(logOutputPath,true); } /** * encoding 编译编码 * jars 需要加载的jar,-classpath选项就是定义class文件的查找目录 * sourceDir java源文件存放目录 * Iterable options = Arrays.asList("-encoding", encoding, "-classpath", jars, "-d", targetDir, "-sourcepath", sourceDir); */ List optionList = new ArrayList<>(); optionList.addAll(Arrays.asList("-classpath",classPath)); optionList.addAll(Arrays.asList("-d",classFileOutputPath)); standardJavaFileManager = compiler.getStandardFileManager(null,null,null); Iterable fileObjects = standardJavaFileManager.getJavaFileObjectsFromStrings(javaFilePathList); JavaCompiler.CompilationTask compilationTask = compiler.getTask(fileWriter,null,null,optionList,null,fileObjects); compileSucceed = compilationTask.call(); }catch (Exception e){ e.printStackTrace(); }finally { if (null != fileWriter){ fileWriter.close(); } if (null != standardJavaFileManager){ standardJavaFileManager.close(); } } if (!compileSucceed){//编译失败 throw new Exception("Compile .java to .class failed"); } } /** * * 类文件打为jar包。 * * @param classFilesPath * @param jarOutputPath */ public static void classFilesToJar(String classFilesPath, String jarOutputPath, String logOutputPath) throws Exception{ List arguments = new ArrayList(); arguments.add("jar"); arguments.add("cvf"); arguments.add(jarOutputPath); arguments.add("-C"); arguments.add(classFilesPath); arguments.add("."); Shell.execute(arguments, logOutputPath); } } ================================================ FILE: GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/tools/ProGuardTool.java ================================================ package com.bzai.gamesdk.build.tools; import com.bzai.gamesdk.build.tools.exec.Shell; import proguard.Configuration; import proguard.ConfigurationParser; import proguard.ProGuard; import java.util.ArrayList; import java.util.List; /** * Created by bzai on 2018/04/20. */ public class ProGuardTool { /** * 混淆jar文件 * * @param inputJar 需要混淆的jar。 * @param classPath 需要混淆的jar所引用的class path. * @param proguardConfigFilePath 混淆配置文件路径。 * @param mappingFileOutputPath mapping 文件输出路径。 * @param outputJar 混淆之后的jar的输出路径。 */ public static void run(String inputJar, String classPath, String proguardConfigFilePath, String mappingFileOutputPath, String outputJar) { String[] commandLineArgs = new String[9]; commandLineArgs[0] = "@"+proguardConfigFilePath; commandLineArgs[1] = "-injars"; commandLineArgs[2] = inputJar; commandLineArgs[3] = "-outjars"; commandLineArgs[4] = outputJar; commandLineArgs[5] = "-printmapping"; commandLineArgs[6] = mappingFileOutputPath; commandLineArgs[7] = "-libraryjars"; commandLineArgs[8] = classPath; Configuration var1 = new Configuration(); for (int i=0;i commandLineArgs = new ArrayList(); commandLineArgs.add("java"); commandLineArgs.add("-jar"); commandLineArgs.add(proguardToolPath); commandLineArgs.add("-injars"); commandLineArgs.add(inputJar); commandLineArgs.add("-outjars"); commandLineArgs.add(outputJar); commandLineArgs.add("-printmapping"); commandLineArgs.add(mappingFileOutputPath); commandLineArgs.add("@"+proguardConfigFilePath); commandLineArgs.add("-libraryjars"); commandLineArgs.add(classPath); Shell.execute(commandLineArgs, proguardLogOutputPath); } } ================================================ FILE: GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/tools/ServerTool.java ================================================ package com.bzai.gamesdk.build.tools; import com.bzai.gamesdk.build.bean.Project; import com.bzai.gamesdk.build.utils.FileUtils; import java.io.File; import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.util.Iterator; import java.util.List; /** * 模拟服务器同步过程 * 一般项目代码都是放到svn或者git上托管的,模拟服务器存储地址 */ public class ServerTool { public static void DownServerResource(List projectList, String checkoutDir) throws IOException{ String root_path = System.getProperty("user.dir"); Iterator iterator = projectList.iterator(); while (iterator.hasNext()){ Project project = iterator.next(); // 获取源码目录 String projectName = project.getName(); String projectUrl = project.getUrl(); String projectResource = root_path + File.separator + projectUrl; // System.out.println(projectResource); // 工作目录 String destPath = checkoutDir + File.separator + projectName ; Path destDirPath = FileSystems.getDefault().getPath(destPath); // System.out.println(destDirPath); boolean destDirPathExists = Files.exists(destDirPath, new LinkOption[]{LinkOption.NOFOLLOW_LINKS}); if (destDirPathExists){ FileUtils.delete(destPath); } FileUtils.copy(projectResource,destPath,false); //设置本地存放路径 project.setPath(destPath); } } } ================================================ FILE: GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/tools/exec/Shell.java ================================================ package com.bzai.gamesdk.build.tools.exec; import com.bzai.gamesdk.build.utils.Utils; import java.io.*; import java.util.List; public class Shell { public static void execute(List commandSet, String logOutput) throws Exception{ Process ps = null; int exitValue = -99; ProcessBuilder builder = new ProcessBuilder(commandSet); ps = builder.start(); OutputStreamWriter outputStreamWriter = null; if (!Utils.isEmpty(logOutput)) { outputStreamWriter = new OutputStreamWriter(new FileOutputStream(logOutput, true)); StreamForwarder errorStream = new StreamForwarder(ps.getErrorStream(), outputStreamWriter, 1, "ERROR"); StreamForwarder outputStream = new StreamForwarder(ps.getInputStream(), outputStreamWriter, 1, "OUTPUT"); errorStream.start(); outputStream.start(); }else{ outputStreamWriter = new OutputStreamWriter(System.out); StreamForwarder errorStream = new StreamForwarder(ps.getErrorStream(), outputStreamWriter, 2, "ERROR"); StreamForwarder outputStream = new StreamForwarder(ps.getInputStream(), outputStreamWriter, 2, "OUTPUT"); errorStream.start(); outputStream.start(); } exitValue = ps.waitFor(); ps.destroy(); if (exitValue != 0){ String inputCommandLine = ""; for (String option:commandSet){ if (!Utils.isEmpty(inputCommandLine)){ inputCommandLine = inputCommandLine + " "; } inputCommandLine = inputCommandLine + option; } throw new Exception("Could not exec command line ["+inputCommandLine+"]"); } } static class StreamForwarder extends Thread{ private final InputStream mIn; private final String mType; private int mStreamType; private final OutputStreamWriter mOs; StreamForwarder(InputStream is, OutputStreamWriter os, int streamType, String type) { mIn = is; mType = type; mOs = os; mStreamType = streamType; } @Override public void run() { BufferedWriter bw = null; BufferedReader br = null; try { bw = new BufferedWriter(mOs); br = new BufferedReader(new InputStreamReader(mIn)); String line; while ((line = br.readLine()) != null) { if (mType.equals("OUTPUT")) { bw.write(line+"\n"); } else { bw.write(line+"\n"); } } } catch (IOException ex) { ex.printStackTrace(); }finally { try{ //使用的是文件流,需要将流关闭。 if (1 == mStreamType){ if (br != null) { br.close(); } if (null != bw){ bw.close(); } } }catch (IOException e){ } } } } } ================================================ FILE: GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/utils/FileUtils.java ================================================ package com.bzai.gamesdk.build.utils; import java.io.File; import java.io.IOException; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.List; /** * 操作文件类 */ public class FileUtils { private static final String TAG = "FileUtils"; public static void fileCopy(String srcPath, String destPath, boolean isReplaceExisting) throws IOException { Path source = FileSystems.getDefault().getPath(srcPath); Path destination = FileSystems.getDefault().getPath(destPath); if (exists(destPath)){ if (isReplaceExisting){ Files.copy(source, destination, StandardCopyOption.REPLACE_EXISTING); } }else{ Files.copy(source, destination, StandardCopyOption.REPLACE_EXISTING); } } /** * smali file copy. * * @param sourcePath * @param destPath * @param filePathList * 如果需要拷贝的文件和 filePathList 文件列表路径下的某个文件的有重复的话, * 拷贝时直接拷贝覆盖 filePathList 文件列表路径下已经存在的文件。 * @throws IOException */ public static void smaliFileCopy(final String appFirstSmaliPath, final String sourcePath, final String destPath, final List filePathList, final List putToMainDexClassList) throws IOException { final Path source = FileSystems.getDefault().getPath(sourcePath); final Path destination = FileSystems.getDefault().getPath(destPath); Files.walkFileTree(source, new SimpleFileVisitor(){ @Override public FileVisitResult preVisitDirectory(Path preVisitDirectoryPath, BasicFileAttributes attrs) throws IOException { Path relativePath = source.relativize(preVisitDirectoryPath); String destPathStr = destination +File.separator +relativePath; Path destPath = FileSystems.getDefault().getPath(destPathStr); boolean pathExists = Files.exists(destPath, new LinkOption[]{ LinkOption.NOFOLLOW_LINKS}); if (!pathExists){ Files.createDirectory(destPath); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Path relativePath = source.relativize(file); String destPathStr = destination +File.separator +relativePath; Path destPath = FileSystems.getDefault().getPath(destPathStr); if (null != putToMainDexClassList && !putToMainDexClassList.isEmpty()){ for (String classPath : putToMainDexClassList){ String putMainDexSmaliPath = sourcePath + File.separator + classPath + ".smali"; String appPutMainDexSmaliPath = appFirstSmaliPath + File.separator + classPath + ".smali"; if(relativePath.toString().equals(classPath + ".smali")){ FileUtils.createFile(appPutMainDexSmaliPath, false); FileUtils.copy(putMainDexSmaliPath, appPutMainDexSmaliPath, true); return FileVisitResult.CONTINUE; } } } boolean isExists = false; if (null != filePathList){ for (String filePath : filePathList){ String destFilePath = filePath.toString() + File.separator + relativePath.toString(); if (FileUtils.exists(destFilePath)){ isExists = true; Files.copy(file, FileSystems.getDefault().getPath(destFilePath), StandardCopyOption.REPLACE_EXISTING); break; } } } if (!isExists){ Files.copy(file, destPath, StandardCopyOption.REPLACE_EXISTING); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { if (null != exc){ exc.printStackTrace(); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { return FileVisitResult.CONTINUE; } }); } /** * file copy * * @param srcPath * @param destPath * @param isReplaceExisting 如果文件存在是否替换 * @throws IOException */ public static void copy(final String srcPath,final String destPath, final boolean isReplaceExisting) throws IOException { final Path source = FileSystems.getDefault().getPath(srcPath); final Path destination = FileSystems.getDefault().getPath(destPath); Files.walkFileTree(source, new SimpleFileVisitor(){ @Override public FileVisitResult preVisitDirectory(Path srcdir, BasicFileAttributes attrs) throws IOException { Path relativizePath = source.relativize(srcdir); String destPathStr = destination +File.separator +relativizePath; Path destPath = FileSystems.getDefault().getPath(destPathStr); boolean pathExists = Files.exists(destPath, new LinkOption[]{ LinkOption.NOFOLLOW_LINKS}); if (!pathExists){ Files.createDirectory(destPath); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Path relativizePath = source.relativize(file); String destPathStr = destination +File.separator +relativizePath; Path destPath = FileSystems.getDefault().getPath(destPathStr); boolean destPathExists = Files.exists(destPath, LinkOption.NOFOLLOW_LINKS); if (destPathExists && !isReplaceExisting){ return FileVisitResult.CONTINUE; } Files.copy(file, destPath, StandardCopyOption.REPLACE_EXISTING); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { if (null != exc){ exc.printStackTrace(); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { return FileVisitResult.CONTINUE; } }); } /** * get special type file list * * @param srcPath path * @param fileType file type * @return file path list * @throws IOException */ public static List getFileList(String srcPath, final String fileType) throws IOException { final Path source = FileSystems.getDefault().getPath(srcPath); final List fileList = new ArrayList(); Files.walkFileTree(source, new SimpleFileVisitor(){ @Override public FileVisitResult preVisitDirectory(Path srcdir, BasicFileAttributes attrs) throws IOException { return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (file.toFile().getName().endsWith(fileType)){ fileList.add(file.toAbsolutePath().toString()); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { return FileVisitResult.CONTINUE; } }); return fileList; } /** * file copy * * @param srcPath source path * @param destPath destination path * @param copyFileType need to copy file type. example .txt or .png * @param isReplaceExisting Whether replace if exist. * @throws IOException */ public static void copy(final String srcPath, final String destPath, final String copyFileType, final boolean isReplaceExisting) throws IOException { final Path source = FileSystems.getDefault().getPath(srcPath); final Path destination = FileSystems.getDefault().getPath(destPath); Files.walkFileTree(source, new SimpleFileVisitor(){ @Override public FileVisitResult preVisitDirectory(Path srcdir, BasicFileAttributes attrs) throws IOException { Path relativizePath = source.relativize(srcdir); String destPathStr = destination +File.separator +relativizePath; Path destPath = FileSystems.getDefault().getPath(destPathStr); boolean pathExists = Files.exists(destPath, new LinkOption[]{ LinkOption.NOFOLLOW_LINKS}); if (!pathExists){ Files.copy(srcdir, destPath, StandardCopyOption.COPY_ATTRIBUTES); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Path relativizePath = source.relativize(file); String destPathStr = destination +File.separator +relativizePath; Path destPath = FileSystems.getDefault().getPath(destPathStr); boolean destPathExists = Files.exists(destPath, LinkOption.NOFOLLOW_LINKS); if (destPathExists && !isReplaceExisting){ return FileVisitResult.CONTINUE; } if (file.toFile().getName().endsWith(copyFileType)){ Files.copy(file, destPath, StandardCopyOption.REPLACE_EXISTING); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { if (null != exc){ exc.printStackTrace(); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { return FileVisitResult.CONTINUE; } }); } /** * file move * * @param srcPath * @param destPath * @throws IOException */ public static void move(String srcPath, String destPath, final boolean isReplaceExisting) throws IOException { final Path source = FileSystems.getDefault().getPath(srcPath); final Path destination = FileSystems.getDefault().getPath(destPath); Files.walkFileTree(source, new SimpleFileVisitor(){ @Override public FileVisitResult preVisitDirectory(Path srcdir, BasicFileAttributes attrs) throws IOException { Path relativizePath = source.relativize(srcdir); String destPathStr = destination +File.separator +relativizePath; Path destPath = FileSystems.getDefault().getPath(destPathStr); boolean pathExists = Files.exists(destPath, new LinkOption[]{ LinkOption.NOFOLLOW_LINKS}); if (!pathExists){ Files.copy(srcdir, destPath, StandardCopyOption.COPY_ATTRIBUTES); }else if(isReplaceExisting){ Files.copy(srcdir, destPath, StandardCopyOption.REPLACE_EXISTING); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Path relativizePath = source.relativize(file); String destPathStr = destination +File.separator +relativizePath; Path destPath = FileSystems.getDefault().getPath(destPathStr); Files.move(file, destPath, StandardCopyOption.REPLACE_EXISTING); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { if (null != exc){ exc.printStackTrace(); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { Files.deleteIfExists(dir); return FileVisitResult.CONTINUE; } }); } /** * Copy * * @param srcPath * @param destPath * @param isRenameExisting * @throws IOException */ public static void copy(final String srcPath,final String destPath, final boolean isRenameExisting, final String prefix) throws IOException { final Path source = FileSystems.getDefault().getPath(srcPath); final Path destination = FileSystems.getDefault().getPath(destPath); Files.walkFileTree(source, new SimpleFileVisitor(){ @Override public FileVisitResult preVisitDirectory(Path srcdir, BasicFileAttributes attrs) throws IOException { Path relativizePath = source.relativize(srcdir); String destPathStr = destination +File.separator +relativizePath; Path destPath = FileSystems.getDefault().getPath(destPathStr); boolean pathExists = Files.exists(destPath, new LinkOption[]{ LinkOption.NOFOLLOW_LINKS}); if (!pathExists){ Files.createDirectory(destPath); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Path relativizePath = source.relativize(file); String destPathStr = destination +File.separator +relativizePath; Path destPath = FileSystems.getDefault().getPath(destPathStr); boolean destPathExists = Files.exists(destPath, LinkOption.NOFOLLOW_LINKS); if (destPathExists && isRenameExisting){ String fileName = destPath.toFile().getName(); String destPathParentPathStr = destPath.toFile().getParentFile().getAbsolutePath(); String newFileName = prefix + fileName; String newFilePathStr = destPathParentPathStr + File.separator + newFileName; while (FileUtils.exists(newFilePathStr)){ newFileName = prefix + newFileName; newFilePathStr = destPathParentPathStr + File.separator + newFileName; } Files.copy(file, FileSystems.getDefault().getPath(newFilePathStr), StandardCopyOption.COPY_ATTRIBUTES); }else{ Files.copy(file, destPath, StandardCopyOption.REPLACE_EXISTING); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { if (null != exc){ exc.printStackTrace(); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { return FileVisitResult.CONTINUE; } }); } /** * delete file. * path can be directory or file * * @param path * @throws IOException */ public static void delete(String path) throws IOException { Path source = FileSystems.getDefault().getPath(path); Files.walkFileTree(source, new SimpleFileVisitor(){ @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Files.delete(file); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { if (null != exc){ exc.printStackTrace(); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { Files.delete(dir); return FileVisitResult.CONTINUE; } }); Files.deleteIfExists(source); } /** * delete child file. * * @param path * @throws IOException */ public static void deleteChildFile(String path) throws IOException { File file = new File(path); File[] files = file.listFiles(); for (File childFile : files){ if (childFile.isDirectory()){ delete(path); }else{ Files.delete(FileSystems.getDefault().getPath(childFile.getAbsolutePath())); } } } /** * delete file. * path can be directory or file * * @param path * @throws IOException */ public static void deleteIfExists(String path) throws IOException { Path source = FileSystems.getDefault().getPath(path); boolean pathExists = Files.exists(source, new LinkOption[]{ LinkOption.NOFOLLOW_LINKS}); if (!pathExists){ return; } Files.walkFileTree(source, new SimpleFileVisitor(){ @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Files.delete(file); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { if (null != exc){ exc.printStackTrace(); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { Files.delete(dir); return FileVisitResult.CONTINUE; } }); Files.deleteIfExists(source); } /** * whether file exists * * @param path * @return */ public static boolean exists(String path){ Path destPath = FileSystems.getDefault().getPath(path); return Files.exists(destPath, new LinkOption[]{ LinkOption.NOFOLLOW_LINKS}); } /** * Create Directories * * @param path * @param isDeleteExists whether delete exits. * @throws IOException */ public static void createDirectories(String path, boolean isDeleteExists) throws IOException { Path destPath = FileSystems.getDefault().getPath(path); boolean pathExists = Files.exists(destPath, new LinkOption[]{ LinkOption.NOFOLLOW_LINKS}); if (pathExists){ if (isDeleteExists){ delete(path); }else{ return; } } Files.createDirectories(destPath); } public static List getAllFilesRelativePath(String filePath){ final List relativizePathList = new ArrayList(); try { final Path sourceFilePath = FileSystems.getDefault().getPath(filePath); Files.walkFileTree(sourceFilePath, new SimpleFileVisitor(){ @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { Path relativizePath = sourceFilePath.relativize(file); relativizePathList.add(relativizePath.toString()); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { return FileVisitResult.CONTINUE; } }); } catch (IOException e) { e.printStackTrace(); } return relativizePathList; } /** * Create directory * * @param path path * @param isDeleteExists whether to delete if file exists. * @throws IOException */ public static void createDirectory(String path, boolean isDeleteExists) throws IOException { Path destPath = FileSystems.getDefault().getPath(path); if (isDeleteExists){ boolean pathExists = Files.exists(destPath, new LinkOption[]{ LinkOption.NOFOLLOW_LINKS}); if (pathExists){ delete(path); } } Files.createDirectory(destPath); } /** * Create directory * * @param path path * @throws IOException */ public static void createDirectory(String path) throws IOException { Path destPath = FileSystems.getDefault().getPath(path); Files.createDirectory(destPath); } /** * Create directories * * @param path path * @throws IOException */ public static void createDirectories(String path) throws IOException { Path destPath = FileSystems.getDefault().getPath(path); Files.createDirectories(destPath); } /** * create directory if non exists * * @param path * @throws IOException */ public static void createDirectoriesIfNonExists(String path) throws IOException { Path destPath = FileSystems.getDefault().getPath(path); boolean pathExists = Files.exists(destPath, new LinkOption[]{ LinkOption.NOFOLLOW_LINKS}); if (pathExists){ return; } Files.createDirectories(destPath); } /** * create directory if non exists * * @param path * @throws IOException */ public static void createDirectoryIfNonExists(String path) throws IOException { Path destPath = FileSystems.getDefault().getPath(path); boolean pathExists = Files.exists(destPath, new LinkOption[]{ LinkOption.NOFOLLOW_LINKS}); if (pathExists){ return; } Files.createDirectory(destPath); } /** * create file * * @param path file path * @param isDeleteIfExists Whether to delete file if exists * @throws IOException */ public static void createFile(String path, boolean isDeleteIfExists) throws IOException { Path filePath = FileSystems.getDefault().getPath(path); boolean filePathExists = Files.exists(filePath, new LinkOption[]{LinkOption.NOFOLLOW_LINKS}); if (filePathExists){ if (isDeleteIfExists){ delete(path); }else{ return; } } File f = new File(path); FileUtils.createDirectoriesIfNonExists(f.getParentFile().getAbsolutePath()); Files.createFile(filePath); } } ================================================ FILE: GameSDKBuildJarTool/src/main/java/com/bzai/gamesdk/build/utils/Utils.java ================================================ package com.bzai.gamesdk.build.utils; import java.io.File; public class Utils { public static final int OK = 0; public static final int ERROR = 10001; private static String OS = System.getProperty("os.name").toLowerCase(); /** * Linux 和 Windows分号分别使用的是":"和";"。 */ public static String OS_SEMICOLON = isWindows()?";":":"; public static boolean isWindows() { return (OS.indexOf("win") >= 0); } public static boolean isEmpty(String str){ if (null != str && !"".equals(str)){ return false; } return true; } /** * Get jar file path list string, use the delimiter to splice. * * @param libsPath * @return */ public static String getJarPathSet(String libsPath, String delimiter){ File file = new File(libsPath); String jarPathSet = ""; File[] files = file.listFiles(); for (int i = 0; i < files.length ; i++) { File libFile = files[i]; if (libFile.getName().endsWith(".jar")){ if (!isEmpty(jarPathSet)){ jarPathSet = jarPathSet + delimiter; } jarPathSet = jarPathSet + libFile.getAbsolutePath(); } } return jarPathSet; } } ================================================ FILE: GameSDKBuildJarTool/src/main/resources/config ================================================ /** * Android sdk 路径。 * 是否必须:必须。 */ androidSdkPath=xxx /** * Android目标SDK版本。 * 是否必须:必须。 */ targetSdkVersion=android-23 /** * * 输出Jar的名称 * 是否必须:必须 */ jarName=sdk_lexiang /** * 输出Jar的版本号 * 是否必须:必须。 */ jarVersion=v1.0.0 /** * 输出路径。 * 是否必须:必须。 */ outPutPath=D:\\BuildJar ================================================ FILE: GameSDKBuildJarTool/src/main/resources/proguard_config.pro ================================================ -dontskipnonpubliclibraryclassmembers -dontshrink -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*,!code/allocation/variable -dontusemixedcaseclassnames -keepattributes SourceFile,LineNumberTable,*Annotation*,Signature,Deprecated,InnerClasses -keepparameternames -renamesourcefileattribute SourceFile -verbose -dontwarn android.support.v4.** # Keep names - Native method names. Keep all native class/method names. -keepclasseswithmembers,allowshrinking class * { native ; } # Also keep - Serialization code. Keep all fields and methods that are used for # serialization. -keepclassmembers class * extends java.io.Serializable { static final long serialVersionUID; static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } #保持 Parcelable 不被混淆 -keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; } # 四大组件 -keep class * extends android.app.Activity { public protected ; ; } -keep class * extends android.app.Application { public protected ; ; } -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver # 对外接口不参与混淆 -keep class com.bzai.gamesdk.GameInfoSetting{ *; } -keep class com.bzai.gamesdk.api.** { *; } -keep class com.bzai.gamesdk.bean.** { *; } -keep class com.bzai.gamesdk.listener.** { *; } # SDK基础不混淆类 -keep class com.bzai.gamesdk.common.utils_base.proguard.** { *; } -keep class * extends com.bzai.gamesdk.common.utils_base.proguard.** { *; } ================================================ FILE: GameSDKBuildJarTool/src/main/resources/project_list ================================================ ###API接口层 GameSDK_API=head,GameSDK_API ###Project项目层 #GameSDK_Project_Custom=head,GameSDK_BeginProject\\GameSDK_Project_Custom GameSDK_Project_JuHe=head,GameSDK_BeginProject\\GameSDK_Project_JuHe ###Channel渠道层 #GameSDK_Channel_Test=head,GameSDK_Channel\\GameSDK_Channel_Test GameSDK_Channel_Lexiang=head,GameSDK_Channel\\GameSDK_Channel_Lexiang ###Manager逻辑控制层 GameSDK_Module_Init=head,GameSDK_Manager\\GameSDK_Module_Init GameSDK_Module_Account=head,GameSDK_Manager\\GameSDK_Module_Account GameSDK_Module_Purchase=head,GameSDK_Manager\\GameSDK_Module_Purchase ###Plugin功能插件层 GameSDK_Manager_Impl=head,GameSDK_Manager_Impl GameSDK_Plugin_Alipay=head,GameSDK_Plugin\\GameSDK_Plugin_Alipay GameSDK_Plugin_Wechat=head,GameSDK_Plugin\\GameSDK_Plugin_Wechat ###基础库 GameSDK_Utils=head,GameSDK_Utils ================================================ FILE: GameSDKBuildJarTool/必读说明 ================================================ ### 该GameSDKBuildJarTool 用于自动化混淆SDK源码工具,只需要配置config、proguard_config_pro、project_list相关配置就可以了。 cmd目录 为手动脚本运行Demo,配合博客来讲解自动化混淆的过程 ================================================ FILE: GameSDKDemo_Release/.gitignore ================================================ /build ================================================ FILE: GameSDKDemo_Release/build.gradle ================================================ apply plugin: 'com.android.application' android { compileSdkVersion 26 buildToolsVersion "27.0.3" defaultConfig { applicationId "com.bzai.gamesdkframe.demo" minSdkVersion 14 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile project(':GameSDKLibrary_Release') } ================================================ FILE: GameSDKDemo_Release/proguard-rules.pro ================================================ # 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 ================================================ FILE: GameSDKDemo_Release/src/androidTest/java/com/bzai/gamesdkframe/ExampleInstrumentedTest.java ================================================ package com.bzai.gamesdkframe; import android.content.Context; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.*; /** * Instrumented test, which will execute on an Android device. * * @see Testing documentation */ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { @Test public void useAppContext() throws Exception { // Context of the app under test. Context appContext = InstrumentationRegistry.getTargetContext(); assertEquals("com.bzai.gamesdkframe", appContext.getPackageName()); } } ================================================ FILE: GameSDKDemo_Release/src/main/AndroidManifest.xml ================================================ ================================================ FILE: GameSDKDemo_Release/src/main/java/com/bzai/gamesdkframe/demo/GameApplication.java ================================================ package com.bzai.gamesdkframe.demo; import android.content.Context; import com.bzai.gamesdk.SDKApplication; /** * Created by bzai on 2018/4/10. *

* Desc: 游戏的Application 直接继承SDK的application */ public class GameApplication extends SDKApplication { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); } @Override public void onCreate() { super.onCreate(); } } ================================================ FILE: GameSDKDemo_Release/src/main/java/com/bzai/gamesdkframe/demo/GameSDKMain.java ================================================ package com.bzai.gamesdkframe.demo; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import com.bzai.gamesdk.GameInfoSetting; import com.bzai.gamesdk.api.SDKAPI; import com.bzai.gamesdk.bean.params.PayParams; import com.bzai.gamesdk.listener.AccountCallBackLister; import com.bzai.gamesdk.listener.ExitCallBackLister; import com.bzai.gamesdk.listener.InitCallBackLister; import com.bzai.gamesdk.listener.PurchaseCallBackListener; import org.json.JSONException; import org.json.JSONObject; import java.util.regex.Pattern; public class GameSDKMain extends Activity implements View.OnClickListener{ private String TAG = getClass().getName(); private EditText etPay,etReport; private TextView tvLog; private int pri = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); init(); } private void initView(){ findViewById(R.id.btn_login).setOnClickListener(this); findViewById(R.id.btn_switchAccount).setOnClickListener(this); findViewById(R.id.btn_logout).setOnClickListener(this); findViewById(R.id.btn_pay).setOnClickListener(this); findViewById(R.id.btn_exit).setOnClickListener(this); etPay = (EditText) findViewById(R.id.et_inputPrice); tvLog = (TextView) findViewById(R.id.tvLog); } @Override public void onClick(View view) { int id = view.getId(); switch (id) { case R.id.btn_login: login(); break; case R.id.btn_switchAccount: switchAccount(); break; case R.id.btn_logout: logout(); break; case R.id.btn_pay: purchase(); break; case R.id.btn_exit: exitGame(); break; default: break; } } private AccountCallBackLister accountCallBackLister = new AccountCallBackLister() { @Override public void onAccountEventCallBack(String jsonStr) { tvLog.setText(jsonStr); showToast(jsonStr); //CP解析数据格式 try { JSONObject jsonObject = new JSONObject(jsonStr); int code = jsonObject.getInt("eventType"); if (code == AccountCallBackLister.LOGIN_SUCCESS || code == AccountCallBackLister.SWITCH_ACCOUNT_SUCCESS){ } } catch (JSONException e) { e.printStackTrace(); } } }; private void init() { //用于配置游戏的 gameid 和 gamekey String gameid = "1"; String gamekey = "222"; GameInfoSetting gameInfoSetting = new GameInfoSetting(gameid,gamekey); SDKAPI.getInstance().init(this, gameInfoSetting,accountCallBackLister, new InitCallBackLister() { @Override public void onSuccess() { tvLog.setText("初始化状态:初始化成功"); showToast("初始化状态:初始化成功"); } @Override public void onFailure(int code, String msg) { String message = "初始化状态" +"\n错误码:\n" + code +"\n错误信息:\n" + msg; tvLog.setText(message); showToast(message); } }); } /** * 账号登陆 */ private void login() { SDKAPI.getInstance().login(this); } /** * 切换账号 */ private void switchAccount(){ SDKAPI.getInstance().switchAccount(this); } /** * 账号登出 */ private void logout() { SDKAPI.getInstance().logout(this); } /** * 购买 */ private void purchase() { String pri_str = etPay.getText().toString(); if (!isDecimal(pri_str) && !isInteger(pri_str)) { showToast("Please enter Correct values."); return; } try { pri = Integer.valueOf(pri_str); } catch (Exception e) { e.printStackTrace(); } /** * productId 商品ID * productName 商品名称 * productDesc 商品描述 * * money 商品单价 (以分为单位) * * roleID 当前游戏内角色ID * roleName 当前游戏内角色名称 * roleLevel 玩家等级 * serverID 当前玩家所在的服务器ID * serverName 当前玩家所在的服务器名称 * * notifyUrl 支付回调地址 * extraInfo 透传给 cp服务器的字段 * gorder CP订单号 */ //商品信息 PayParams payParams = new PayParams(); payParams.setProductName("金币"); payParams.setProductDesc("一金币等于十银币"); payParams.setProductId("9000"); //SDK的商品ID //金额信息 payParams.setMoney(pri); //玩家信息 payParams.setRoleID("123456"); payParams.setRoleName("小明"); payParams.setRoleLevel("15"); payParams.setServerID("11"); payParams.setServerName("服务十一区"); //支付配置信息 payParams.setNotifyUrl("www.baidu.com"); payParams.setExtension("extra"); payParams.setGorder("DD123456"); SDKAPI.getInstance().pay(this, payParams,new PurchaseCallBackListener() { //创建SDK订单成功就返回,方便CP查询该笔订单状态 @Override public void onOrderId(String orderId) { showToast(orderId); } @Override public void onSuccess() { String message = "支付成功"; tvLog.setText(message); showToast(message); } @Override public void onFailure(int code, String msg) { String message = "支付失败\n:\n错误:\n" + code; tvLog.setText(message); showToast(message); } @Override public void onCancel() { String message = "支付取消\n:\n错误:\n" ; tvLog.setText(message); showToast(message); } //支付完成,没有正确支付回调时,会返回该结果 @Override public void onComplete() { String message = "支付完成\n" ; tvLog.setText(message); showToast(message); } }); } //--------------------------------------------------退出接口--------------------------------------------- private void exitGame(){ SDKAPI.getInstance().exit(GameSDKMain.this,new ExitCallBackLister(){ //存在退出框,并且点击退出成功 @Override public void onExitDialogSuccess() { Log.d(TAG,"退出成功"); SDKAPI.getInstance().onDestroy(GameSDKMain.this); System.exit(0); } //存在退出框,并且点击取消退出 @Override public void onExitDialogCancel() { Log.d(TAG,"退出取消"); } //不存在退出框,需要游戏自己实现退出框,然后调用SDK释放资源接口 @Override public void onNotExitDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(GameSDKMain.this); builder.setTitle("退出游戏"); builder.setPositiveButton("退出", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { SDKAPI.getInstance().onDestroy(GameSDKMain.this); System.exit(0); } }); builder.show(); } }); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: exitGame(); break; } return super.onKeyDown(keyCode, event); } @Override public void onBackPressed() { super.onBackPressed(); exitGame(); } private void showToast(String msg) { Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); } // 浮点型判断 (Floating-point judgment) public static boolean isDecimal(String str) { if (str == null || "".equals(str)) return false; java.util.regex.Pattern pattern = Pattern.compile("[0-9]*(\\.?)[0-9]*"); return pattern.matcher(str).matches(); } // 整型判断 (Integer to determine) public static boolean isInteger(String str) { if (str == null) return false; Pattern pattern = Pattern.compile("[0-9]+"); return pattern.matcher(str).matches(); } //--------------------------------------------------生命周期接口--------------------------------------------- @Override protected void onStart() { super.onStart(); SDKAPI.getInstance().onStart(GameSDKMain.this); } @Override protected void onResume() { super.onResume(); SDKAPI.getInstance().onResume(GameSDKMain.this); } @Override protected void onPause() { super.onPause(); SDKAPI.getInstance().onPause(GameSDKMain.this); } @Override protected void onStop() { super.onStop(); SDKAPI.getInstance().onStop(GameSDKMain.this); } @Override protected void onRestart() { super.onRestart(); SDKAPI.getInstance().onRestart(GameSDKMain.this); } @Override protected void onDestroy() { super.onDestroy(); SDKAPI.getInstance().onDestroy(GameSDKMain.this); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); SDKAPI.getInstance().onNewIntent(GameSDKMain.this,intent); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); SDKAPI.getInstance().onActivityResult(GameSDKMain.this,requestCode,resultCode,data); } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); SDKAPI.getInstance().onRequestPermissionsResult(GameSDKMain.this,requestCode, permissions, grantResults); } } ================================================ FILE: GameSDKDemo_Release/src/main/res/layout/activity_main.xml ================================================