设置OriginMaster提交点合并APPBase源码。
							
								
								
									
										87
									
								
								.github/workflows/android.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,87 @@ | ||||
| name: Android CI | ||||
|  | ||||
| # 触发器 | ||||
| on: | ||||
|   push: | ||||
|     tags: | ||||
|       - *-beta | ||||
|   pull_request: | ||||
|     tags: | ||||
|       - *-beta | ||||
|  | ||||
| jobs: | ||||
|   build: | ||||
|  | ||||
|     runs-on: ubuntu-latest | ||||
|      | ||||
|     # 设置 JDK 环境 | ||||
|     steps: | ||||
|     - uses: actions/checkout@v3 | ||||
|     - name: set up JDK 11 | ||||
|       uses: actions/setup-java@v3 | ||||
|       with: | ||||
|         java-version: '11' | ||||
|         distribution: 'temurin' | ||||
|         cache: gradle | ||||
|      | ||||
|     - name: Grant execute permission for gradlew | ||||
|       run: chmod +x gradlew | ||||
|        | ||||
|     # 获取应用打包秘钥库 | ||||
|     - name: Checkout Android Keystore | ||||
|       uses: actions/checkout@v3 | ||||
|       with: | ||||
|         repository: zhangsken/keystore # 存储应用打包用的 keystore 的仓库(格式:用户名/仓库名) | ||||
|         token: ${{ secrets.APP_SECRET_TOKEN_1 }} # 连接仓库的 token , 需要单独配置 | ||||
|         path: keystore # 仓库的根目录名 | ||||
|          | ||||
|     # 打包 Stage Release 版本应用 | ||||
|     - name: Build with Gradle | ||||
|       run: bash ./gradlew assembleBetaRelease | ||||
|     # 创建release | ||||
|     - name: Create Release | ||||
|       id: create_release | ||||
|       uses: actions/create-release@v1 | ||||
|       env: | ||||
|         GITHUB_TOKEN: ${{ secrets.APP_SECRET_TOKEN_1 }} | ||||
|         # GitHub 会自动创建 GITHUB_TOKEN 密码以在工作流程中使用。  | ||||
|         # 您可以使用 GITHUB_TOKEN 在工作流程运行中进行身份验证。 | ||||
|         # 当您启用 GitHub Actions 时,GitHub 在您的仓库中安装 GitHub 应用程序。  | ||||
|         # GITHUB_TOKEN 密码是一种 GitHub 应用程序 安装访问令牌。  | ||||
|         # 您可以使用安装访问令牌代表仓库中安装的 GitHub 应用程序 进行身份验证。  | ||||
|         # 令牌的权限仅限于包含您的工作流程的仓库。 更多信息请参阅“GITHUB_TOKEN 的权限”。 | ||||
|         # 在每个作业开始之前, GitHub 将为作业提取安装访问令牌。 令牌在作业完成后过期。 | ||||
|       with: | ||||
|         tag_name: ${{ github.ref }} | ||||
|         release_name: Release ${{ github.ref }} | ||||
|         draft: false | ||||
|         prerelease: false | ||||
|          | ||||
|     # 获取 APK 版本号 | ||||
|     - name: Get Version Name | ||||
|       uses: actions/github-script@v3 | ||||
|       id: get-version | ||||
|       with: | ||||
|         script: | | ||||
|           const str=process.env.GITHUB_REF; | ||||
|           return str.substring(str.indexOf("v")); | ||||
|         result-encoding: string | ||||
|     # 上传至 Release 的资源 | ||||
|     - name: Upload Release Asset | ||||
|       id: upload-release-asset  | ||||
|       uses: actions/upload-release-asset@v1 | ||||
|       env: | ||||
|         GITHUB_TOKEN: ${{ secrets.APP_SECRET_TOKEN_1 }} | ||||
|       with: | ||||
|         upload_url: ${{ steps.create_release.outputs.upload_url }} # 上传网址,无需改动 | ||||
|         #asset_path: app/build/outputs/apk/release/app-release.apk # 上传路径(Release) | ||||
|         asset_path: app/build/outputs/apk/beta/release/app-beta-release.apk # 上传路径(WinBoll Stage Release) | ||||
|         asset_name: WinBoll-${{steps.get-version.outputs.result}}0.apk # 资源名 | ||||
|         asset_content_type: application/vnd.android.package-archiv # 资源类型 | ||||
|          | ||||
|     # 存档打包的文件 | ||||
|     - name: Archive production artifacts | ||||
|       uses: actions/upload-artifact@v2 | ||||
|       with: | ||||
|         name: build | ||||
|         path: app/build/outputs # 将打包之后的文件全部上传(里面会有混淆的 map 文件) | ||||
							
								
								
									
										105
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,105 @@ | ||||
| # Built application files | ||||
| *.apk | ||||
| *.aar | ||||
| *.ap_ | ||||
| *.aab | ||||
|  | ||||
| # Files for the ART/Dalvik VM | ||||
| *.dex | ||||
|  | ||||
| # Java class files | ||||
| *.class | ||||
|  | ||||
| # Generated files | ||||
| bin/ | ||||
| gen/ | ||||
| out/ | ||||
| #  Uncomment the following line in case you need and you don't have the release build type files in your app | ||||
| # release/ | ||||
|  | ||||
| # Gradle files | ||||
| .gradle/ | ||||
| build/ | ||||
|  | ||||
| # Local configuration file (sdk path, etc) | ||||
| local.properties | ||||
|  | ||||
| # Proguard folder generated by Eclipse | ||||
| proguard/ | ||||
|  | ||||
| # Log Files | ||||
| *.log | ||||
|  | ||||
| # Android Studio Navigation editor temp files | ||||
| .navigation/ | ||||
|  | ||||
| # Android Studio captures folder | ||||
| captures/ | ||||
|  | ||||
| # IntelliJ | ||||
| *.iml | ||||
| .idea/workspace.xml | ||||
| .idea/tasks.xml | ||||
| .idea/gradle.xml | ||||
| .idea/assetWizardSettings.xml | ||||
| .idea/dictionaries | ||||
| .idea/libraries | ||||
| # Android Studio 3 in .gitignore file. | ||||
| .idea/caches | ||||
| .idea/modules.xml | ||||
| # Comment next line if keeping position of elements in Navigation Editor is relevant for you | ||||
| .idea/navEditor.xml | ||||
|  | ||||
| # Keystore files | ||||
| # Uncomment the following lines if you do not want to check your keystore files in. | ||||
| *.jks | ||||
| *.keystore | ||||
|  | ||||
| # External native build folder generated in Android Studio 2.2 and later | ||||
| .externalNativeBuild | ||||
| .cxx/ | ||||
|  | ||||
| # Google Services (e.g. APIs or Firebase) | ||||
| # google-services.json | ||||
|  | ||||
| # Freeline | ||||
| freeline.py | ||||
| freeline/ | ||||
| freeline_project_description.json | ||||
|  | ||||
| # fastlane | ||||
| fastlane/report.xml | ||||
| fastlane/Preview.html | ||||
| fastlane/screenshots | ||||
| fastlane/test_output | ||||
| fastlane/readme.md | ||||
|  | ||||
| # Version control | ||||
| vcs.xml | ||||
|  | ||||
| # lint | ||||
| lint/intermediates/ | ||||
| lint/generated/ | ||||
| lint/outputs/ | ||||
| lint/tmp/ | ||||
| # lint/reports/ | ||||
|  | ||||
| # Android Profiling | ||||
| *.hprof | ||||
|  | ||||
| # Custom | ||||
| .androidide | ||||
| lint-results.xml | ||||
| lint-results.html | ||||
| winboll.properties | ||||
| local.properties | ||||
|  | ||||
| ## 忽略模块应用编译配置 | ||||
| /settings.gradle | ||||
| /gradle.properties | ||||
|  | ||||
| ## 忽略 srv 纠结问题 | ||||
| /srv/ | ||||
|  | ||||
| ## 忽略 winboll-x 文件夹 | ||||
| /winboll-x/ | ||||
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,3 @@ | ||||
| [submodule "libjc/jcc/libs"] | ||||
| 	path = libjc/jcc/libs | ||||
| 	url = https://gitea.winboll.cc/Studio/APP_libjc_jcc_libs.git | ||||
							
								
								
									
										3
									
								
								.idea/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,3 @@ | ||||
| # Default ignored files | ||||
| /shelf/ | ||||
| /workspace.xml | ||||
							
								
								
									
										1
									
								
								.idea/.name
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| appbase | ||||
							
								
								
									
										6
									
								
								.idea/compiler.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="CompilerConfiguration"> | ||||
|     <bytecodeTargetLevel target="17" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										10
									
								
								.idea/deploymentTargetDropDown.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,10 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="deploymentTargetDropDown"> | ||||
|     <value> | ||||
|       <entry key="appbase"> | ||||
|         <State /> | ||||
|       </entry> | ||||
|     </value> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										10
									
								
								.idea/migrations.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,10 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="ProjectMigrations"> | ||||
|     <option name="MigrateToGradleLocalJavaHome"> | ||||
|       <set> | ||||
|         <option value="$PROJECT_DIR$" /> | ||||
|       </set> | ||||
|     </option> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										10
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,10 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="ExternalStorageConfigurationManager" enabled="true" /> | ||||
|   <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK"> | ||||
|     <output url="file://$PROJECT_DIR$/build/classes" /> | ||||
|   </component> | ||||
|   <component name="ProjectType"> | ||||
|     <option name="id" value="Android" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										18
									
								
								.winboll/Readme.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,18 @@ | ||||
| ## WinBoLL 主机编译事项提醒 | ||||
|  | ||||
| ## 类库类型源码发布 | ||||
| # 类库发布使用以下面命令 | ||||
| git pull && bash .winboll/bashPublishLIBAddTag.sh <类库模块文件夹名称> | ||||
|  | ||||
| ## 纯应用类型源码发布 | ||||
| # 应用发布使用以下命令 | ||||
| git pull && bash .winboll/bashPublishAPKAddTag.sh <应用模块文件夹名称> | ||||
|  | ||||
| ## 编译时提问。Add Github Workflows Tag? (yes/No) | ||||
| 回答yes: 将会添加一个 GitHub 工作流标签 | ||||
|         GitHub 仓库会执行以该标签为标志的编译工作流。 | ||||
| 回答No(默认): 就忽略 GitHub 标签,忽略 GitHub 工作流调用。 | ||||
|  | ||||
| ## Github Workflows 工作流设置注意事项 | ||||
| 应用名称改变时需要修改.github/workflows/android.yml文件设置, | ||||
| 在第79行:asset_name: 处有应用包名称设置。 | ||||
							
								
								
									
										3
									
								
								.winboll/bashChangeToBetaKeyStore.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,3 @@ | ||||
| #!/bin/usr/bash | ||||
| ## Change Back To Beta KeyStore in keystore module. | ||||
| cd keystore;git reset --hard f5bc75ff45fcb8894b5bd3f49b91bdd8fe3c317e;cd .. | ||||
							
								
								
									
										3
									
								
								.winboll/bashChangeToStageMGKeyStore.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,3 @@ | ||||
| #!/bin/usr/bash | ||||
| ## Change Back To StageMG KeyStore in keystore module. | ||||
| cd keystore;git reset --hard d22519b11253f85f495400b01b6373e9657defb4;cd .. | ||||
							
								
								
									
										32
									
								
								.winboll/bashCheckGitCommitStatus.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,32 @@ | ||||
| #!/usr/bin/bash | ||||
|  | ||||
| # 使用 `-z` 命令检查变量是否为空 | ||||
| if [ -z "$1" ] || [ -z "$2" ]; then | ||||
|     echo "Script parameter error: $0" | ||||
|     exit 2 | ||||
| fi | ||||
|  | ||||
| # 进入项目根目录 | ||||
| cd ${1} | ||||
| echo -e "Work dir : \n"`pwd` | ||||
|  | ||||
| git config --global --add safe.directory "${1}" | ||||
| echo "Current dir : "`pwd` | ||||
| versionName=${2} | ||||
|  | ||||
| ## 设置要检查的标签 | ||||
| tag="v"${versionName} | ||||
|  | ||||
| ## 如果Git已经提交了所有代码就执行标签检查操作 | ||||
| if [[ -n $(git diff --stat)  ]] | ||||
| then | ||||
|   echo 'Source is no commit git completely, tag action cancel.' | ||||
|   exit 1 | ||||
| else | ||||
|   echo "Git status is clean." | ||||
|   if [ "$(git tag -l ${tag})" == "${tag}" ]; then | ||||
|       echo "Tag ${tag} exist." | ||||
|       exit 2 | ||||
|   fi | ||||
|   echo "${0}: Git tag is checked OK: (${tag})" | ||||
| fi | ||||
							
								
								
									
										17
									
								
								.winboll/bashCommitAppPublishBuildFlagInfo.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,17 @@ | ||||
| #!/usr/bin/bash | ||||
| ## 提交新的 APK 编译配置标志信息,并推送到Git仓库。 | ||||
|  | ||||
| # 使用 `-z` 命令检查变量是否为空 | ||||
| if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ]; then | ||||
|     echo "$0 Script parameter error." | ||||
|     echo "(Script Demo : [ bashCommitAppPublishBuildFlagInfo.sh <RootProjectDir> <VersionName> <BuildType Name> <RootProject Name> ])" | ||||
|     exit 2 | ||||
| fi | ||||
|  | ||||
| # 进入项目根目录 | ||||
| cd ${1} | ||||
| echo -e "Work dir : \n"`pwd` | ||||
|  | ||||
| git add . | ||||
| git commit -m "<$4>APK ${2} ${3} Publish." | ||||
| git push origin && git push origin --tags | ||||
							
								
								
									
										48
									
								
								.winboll/bashCommitLibReleaseBuildFlagInfo.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,48 @@ | ||||
| #!/usr/bin/bash | ||||
| ## 提交新的 Library 编译配置标志信息,并推送到Git仓库。 | ||||
|  | ||||
| # 检查是否指定了将要发布的类库名称 | ||||
| # 使用 `-z` 命令检查变量是否为空 | ||||
| if [ -z "$1" ]; then | ||||
|     echo "Library name error: $0" | ||||
|     exit 2 | ||||
| fi | ||||
|  | ||||
| ## 开始执行脚本 | ||||
| echo -e "Current dir : \n"`pwd` | ||||
| # 检查当前目录是否是项目根目录 | ||||
| if [[ -e $1/build.properties ]]; then | ||||
|     echo "The $1/build.properties file exists." | ||||
|     echo -e "Work dir correctly." | ||||
| else | ||||
|     echo "The $1/build.properties file does not exist." | ||||
|     echo "尝试进入根目录" | ||||
|     # 进入项目根目录 | ||||
|     cd .. | ||||
| fi | ||||
| ## 本脚本需要在项目根目录下执行 | ||||
| echo -e "Current dir : \n"`pwd` | ||||
| # 检查当前目录是否是项目根目录 | ||||
| if [[ -e $1/build.properties ]]; then | ||||
|     echo "The $1/build.properties file exists." | ||||
|     echo -e "Work dir correctly." | ||||
| else | ||||
|     echo "The $1/build.properties file does not exist." | ||||
|     echo -e "Work dir error." | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| # 就读取脚本 .winboll/winboll_app_build.gradle 生成的 publishVersion。 | ||||
| # 如果文件中有 publishVersion 这一项, | ||||
| # 使用grep找到包含"publishVersion="的那一行,然后用awk提取其后的值 | ||||
| PUBLISH_VERSION=$(grep -o "publishVersion=.*" $1/build.properties | awk -F '=' '{print $2}') | ||||
| echo "< $1/build.properties publishVersion : ${PUBLISH_VERSION} >" | ||||
| ## 设新的 WinBoLL 标签 | ||||
| # 脚本调试时使用 | ||||
| #tag="v7.6.4-test1" | ||||
| # 正式设置标签时使用 | ||||
| #tag="v"${PUBLISH_VERSION} | ||||
|  | ||||
| git add . | ||||
| git commit -m "<$1>Library Release ${PUBLISH_VERSION}" | ||||
| git push origin && git push origin --tags | ||||
							
								
								
									
										166
									
								
								.winboll/bashPublishAPKAddTag.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,166 @@ | ||||
| #!/usr/bin/bash | ||||
|  | ||||
| # 检查是否指定了将要发布的应用名称 | ||||
| # 使用 `-z` 命令检查变量是否为空 | ||||
| if [ -z "$1" ]; then | ||||
|     echo "No APP name specified : $0" | ||||
|     exit 2 | ||||
| fi | ||||
|  | ||||
| ## 定义相关函数 | ||||
| ## 检查 Git 源码是否完全提交了,完全提交就返回0 | ||||
| function checkGitSources { | ||||
|     #local input="$1" | ||||
|     #echo "The string is: $input" | ||||
| 	git config --global --add safe.directory `pwd` | ||||
| 	if [[ -n $(git diff --stat)  ]] | ||||
|     then | ||||
| 		local result="Source is no commit completely." | ||||
| 	    echo $result | ||||
| 	    # 脚本调试时使用 | ||||
| 	    #return 0 | ||||
| 	    # 正式检查源码时使用 | ||||
| 	    return 1 | ||||
|     fi | ||||
|     local result="Git Source Check OK." | ||||
| 	echo $result | ||||
|     return 0 | ||||
| } | ||||
|  | ||||
| function askAddWorkflowsTag { | ||||
| 	read answer | ||||
| 	if [[ $answer =~ ^[Yy]$ ]]; then | ||||
| 	    #echo "You chose yes." | ||||
| 	    return 1 | ||||
| 	else | ||||
| 	    #echo "You chose no." | ||||
| 	    return 0 | ||||
| 	fi | ||||
| } | ||||
|  | ||||
| function addWinBoLLTag { | ||||
| 	# 就读取脚本 .winboll/winboll_app_build.gradle 生成的 publishVersion。 | ||||
|     # 如果文件中有 publishVersion 这一项, | ||||
| 	# 使用grep找到包含"publishVersion="的那一行,然后用awk提取其后的值 | ||||
| 	PUBLISH_VERSION=$(grep -o "publishVersion=.*" $1/build.properties | awk -F '=' '{print $2}') | ||||
| 	echo "< $1/build.properties publishVersion : ${PUBLISH_VERSION} >" | ||||
| 	## 设新的 WinBoLL 标签 | ||||
| 	# 脚本调试时使用 | ||||
| 	#tag="projectname-v7.6.4-test1" | ||||
| 	# 正式设置标签时使用 | ||||
| 	tag=$1"-v"${PUBLISH_VERSION} | ||||
| 	echo "< WinBoLL Tag To: $tag >"; | ||||
| 	# 检查是否已经添加了 WinBoLL Tag | ||||
| 	if [ "$(git tag -l ${tag})" == "${tag}" ]; then | ||||
|         echo -e "< WinBoLL Tag ${tag} exist! >" | ||||
|         return 1 # WinBoLL标签重复 | ||||
|     fi | ||||
|     # 添加WinBoLL标签 | ||||
| 	git tag -a ${tag} -F $1/app_update_description.txt | ||||
|     return 0 | ||||
| } | ||||
|  | ||||
| function addWorkflowsTag { | ||||
| 	# 就读取脚本 .winboll/winboll_app_build.gradle 生成的 baseBetaVersion。 | ||||
|     # 如果文件中有 baseBetaVersion 这一项, | ||||
| 	# 使用grep找到包含"baseBetaVersion="的那一行,然后用awk提取其后的值 | ||||
| 	BASE_BETA_VERSION=$(grep -o "baseBetaVersion=.*" $1/build.properties | awk -F '=' '{print $2}') | ||||
| 	echo "< $1/build.properties baseBetaVersion : ${BASE_BETA_VERSION} >" | ||||
| 	## 设新的 workflows 标签 | ||||
| 	# 脚本调试时使用 | ||||
| 	#tag="projectname-v7.6.4-beta" | ||||
| 	# 正式设置标签时使用 | ||||
| 	tag=$1"-v"${BASE_BETA_VERSION}-beta | ||||
| 	echo "< Workflows Tag To: $tag >"; | ||||
| 	# 检查是否已经添加了工作流 Tag | ||||
| 	if [ "$(git tag -l ${tag})" == "${tag}" ]; then | ||||
|         echo -e "< Github Workflows Tag ${tag} exist! >" | ||||
|         return 1 # 工作流标签重复 | ||||
|     fi | ||||
|     # 添加工作流标签 | ||||
| 	git tag -a ${tag} -F $1/app_update_description.txt | ||||
|     return 0 | ||||
| } | ||||
|  | ||||
| ## 开始执行脚本 | ||||
| echo -e "Current dir : \n"`pwd` | ||||
| # 检查当前目录是否是项目根目录 | ||||
| if [[ -e $1/build.properties ]]; then | ||||
|     echo "The $1/build.properties file exists." | ||||
|     echo -e "Work dir correctly." | ||||
| else | ||||
|     echo "The $1/build.properties file does not exist." | ||||
|     echo "尝试进入根目录" | ||||
|     # 进入项目根目录 | ||||
|     cd .. | ||||
| fi | ||||
| ## 本脚本需要在项目根目录下执行 | ||||
| echo -e "Current dir : \n"`pwd` | ||||
| # 检查当前目录是否是项目根目录 | ||||
| if [[ -e $1/build.properties ]]; then | ||||
|     echo "The $1/build.properties file exists." | ||||
|     echo -e "Work dir correctly." | ||||
| else | ||||
|     echo "The $1/build.properties file does not exist." | ||||
|     echo -e "Work dir error." | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| # 检查源码状态 | ||||
| result=$(checkGitSources) | ||||
| if [[ $? -eq 0 ]]; then | ||||
|     echo $result | ||||
|     # 如果Git已经提交了所有代码就执行标签和应用发布操作 | ||||
|  | ||||
|     # 预先询问是否添加工作流标签 | ||||
|     echo "Add Github Workflows Tag? (yes/No)" | ||||
| 	result=$(askAddWorkflowsTag) | ||||
| 	nAskAddWorkflowsTag=$? | ||||
| 	echo $result | ||||
|  | ||||
|     # 发布应用 | ||||
| 	echo "Publishing WinBoLL APK ..." | ||||
| 	# 脚本调试时使用 | ||||
| 	#bash gradlew :$1:assembleBetaDebug | ||||
| 	# 正式发布 | ||||
|     bash gradlew :$1:assembleStageRelease | ||||
|     echo "Publishing WinBoLL APK OK." | ||||
|      | ||||
|     # 添加 WinBoLL 标签 | ||||
|     result=$(addWinBoLLTag $1) | ||||
|     echo $result | ||||
| 	if [[ $? -eq 0 ]]; then | ||||
| 	    echo $result | ||||
|     	# WinBoLL 标签添加成功 | ||||
| 	else | ||||
|     	echo -e "${0}: addWinBoLLTag $1\n${result}\nAdd WinBoLL tag cancel." | ||||
|         exit 1 # addWinBoLLTag 异常 | ||||
| 	fi | ||||
|      | ||||
|     # 添加 GitHub 工作流标签 | ||||
| 	if [[ $nAskAddWorkflowsTag -eq 1 ]]; then | ||||
| 	    # 如果用户选择添加工作流标签 | ||||
|     	result=$(addWorkflowsTag $1) | ||||
| 		if [[ $? -eq 0 ]]; then | ||||
| 		    echo $result | ||||
| 		    # 工作流标签添加成功 | ||||
| 		else | ||||
| 			echo -e "${0}: addWorkflowsTag $1\n${result}\nAdd workflows tag cancel." | ||||
| 			exit 1 # addWorkflowsTag 异常 | ||||
| 		fi | ||||
| 	fi | ||||
| 	 | ||||
| 	## 清理更新描述文件内容 | ||||
| 	echo "" > $1/app_update_description.txt | ||||
| 	 | ||||
| 	# 设置新版本开发参数配置 | ||||
| 	# 提交配置 | ||||
| 	git add . | ||||
| 	git commit -m "<$1>Start New Stage Version." | ||||
| 	echo "Push sources to git repositories ..." | ||||
|     # 推送源码到所有仓库 | ||||
|     git push origin && git push origin --tags | ||||
| else | ||||
| 	echo -e "${0}: checkGitSources\n${result}\nShell cancel." | ||||
| 	exit 1 # checkGitSources 异常 | ||||
| fi | ||||
							
								
								
									
										166
									
								
								.winboll/bashPublishDebugAPKAddTag.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,166 @@ | ||||
| #!/usr/bin/bash | ||||
|  | ||||
| # 检查是否指定了将要发布的调试版应用名称 | ||||
| # 使用 `-z` 命令检查变量是否为空 | ||||
| if [ -z "$1" ]; then | ||||
|     echo "No APP name specified : $0" | ||||
|     exit 2 | ||||
| fi | ||||
|  | ||||
| ## 定义相关函数 | ||||
| ## 检查 Git 源码是否完全提交了,完全提交就返回0 | ||||
| function checkGitSources { | ||||
|     #local input="$1" | ||||
|     #echo "The string is: $input" | ||||
|     git config --global --add safe.directory `pwd` | ||||
|     if [[ -n $(git diff --stat)  ]] | ||||
|     then | ||||
|         local result="Source is no commit completely." | ||||
|         echo $result | ||||
|         # 脚本调试时使用 | ||||
|         #return 0 | ||||
|         # 正式检查源码时使用 | ||||
|         return 1 | ||||
|     fi | ||||
|     local result="Git Source Check OK." | ||||
|     echo $result | ||||
|     return 0 | ||||
| } | ||||
|  | ||||
| function askAddWorkflowsTag { | ||||
|     read answer | ||||
|     if [[ $answer =~ ^[Yy]$ ]]; then | ||||
|         #echo "You chose yes." | ||||
|         return 1 | ||||
|     else | ||||
|         #echo "You chose no." | ||||
|         return 0 | ||||
|     fi | ||||
| } | ||||
|  | ||||
| function addWinBoLLTag { | ||||
|     # 就读取脚本 .winboll/winboll_app_build.gradle 生成的 publishVersion。 | ||||
|     # 如果文件中有 publishVersion 这一项, | ||||
|     # 使用grep找到包含"publishVersion="的那一行,然后用awk提取其后的值 | ||||
|     PUBLISH_VERSION=$(grep -o "publishVersion=.*" $1/build.properties | awk -F '=' '{print $2}') | ||||
|     echo "< $1/build.properties publishVersion : ${PUBLISH_VERSION} >" | ||||
|     ## 设新的 WinBoLL 标签 | ||||
|     # 脚本调试时使用 | ||||
|     #tag="v7.6.4-test1" | ||||
|     # 正式调试版设置标签时使用 | ||||
|     tag=$1"-v"${PUBLISH_VERSION}"-debug" | ||||
|     echo "< WinBoLL Tag To: $tag >"; | ||||
|     # 检查是否已经添加了 WinBoLL Tag | ||||
|     if [ "$(git tag -l ${tag})" == "${tag}" ]; then | ||||
|         echo -e "< WinBoLL Tag ${tag} exist! >" | ||||
|         return 1 # WinBoLL标签重复 | ||||
|     fi | ||||
|     # 添加WinBoLL标签 | ||||
|     git tag -a ${tag} -F $1/app_update_description.txt | ||||
|     return 0 | ||||
| } | ||||
|  | ||||
| function addWorkflowsTag { | ||||
|     # 就读取脚本 .winboll/winboll_app_build.gradle 生成的 baseBetaVersion。 | ||||
|     # 如果文件中有 baseBetaVersion 这一项, | ||||
|     # 使用grep找到包含"baseBetaVersion="的那一行,然后用awk提取其后的值 | ||||
|     BASE_BETA_VERSION=$(grep -o "baseBetaVersion=.*" $1/build.properties | awk -F '=' '{print $2}') | ||||
|     echo "< $1/build.properties baseBetaVersion : ${BASE_BETA_VERSION} >" | ||||
|     ## 设新的 workflows 标签 | ||||
|     # 脚本调试时使用 | ||||
|     #tag="v7.6.4-beta" | ||||
|     # 正式设置标签时使用 | ||||
|     tag=$1"-"v"${BASE_BETA_VERSION}-beta-debug | ||||
|     echo "< Workflows Tag To: $tag >"; | ||||
|     # 检查是否已经添加了工作流 Tag | ||||
|     if [ "$(git tag -l ${tag})" == "${tag}" ]; then | ||||
|         echo -e "< Github Workflows Tag ${tag} exist! >" | ||||
|         return 1 # 工作流标签重复 | ||||
|     fi | ||||
|     # 添加工作流标签 | ||||
|     git tag -a ${tag} -F $1/app_update_description.txt | ||||
|     return 0 | ||||
| } | ||||
|  | ||||
| ## 开始执行脚本 | ||||
| echo -e "Current dir : \n"`pwd` | ||||
| # 检查当前目录是否是项目根目录 | ||||
| if [[ -e $1/build.properties ]]; then | ||||
|     echo "The $1/build.properties file exists." | ||||
|     echo -e "Work dir correctly." | ||||
| else | ||||
|     echo "The $1/build.properties file does not exist." | ||||
|     echo "尝试进入根目录" | ||||
|     # 进入项目根目录 | ||||
|     cd .. | ||||
| fi | ||||
| ## 本脚本需要在项目根目录下执行 | ||||
| echo -e "Current dir : \n"`pwd` | ||||
| # 检查当前目录是否是项目根目录 | ||||
| if [[ -e $1/build.properties ]]; then | ||||
|     echo "The $1/build.properties file exists." | ||||
|     echo -e "Work dir correctly." | ||||
| else | ||||
|     echo "The $1/build.properties file does not exist." | ||||
|     echo -e "Work dir error." | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| # 检查源码状态 | ||||
| result=$(checkGitSources) | ||||
| if [[ $? -eq 0 ]]; then | ||||
|     echo $result | ||||
|     # 如果Git已经提交了所有代码就执行标签和应用发布操作 | ||||
|  | ||||
|     # 预先询问是否添加工作流标签 | ||||
|     echo "Add Github Workflows Tag? (yes/no)" | ||||
|     result=$(askAddWorkflowsTag) | ||||
|     nAskAddWorkflowsTag=$? | ||||
|     echo $result | ||||
|  | ||||
|     # 发布应用 | ||||
|     echo "Publishing WinBoLL Debug APK ..." | ||||
|     # 脚本调试时使用 | ||||
|     #bash gradlew :$1:assembleBetaDebug | ||||
|     # 正式发布调试版 | ||||
|     bash gradlew :$1:assembleStageDebug | ||||
|     echo "Publishing WinBoLL Debug APK OK." | ||||
|      | ||||
|     # 添加 WinBoLL 标签 | ||||
|     result=$(addWinBoLLTag $1) | ||||
|     echo $result | ||||
|     if [[ $? -eq 0 ]]; then | ||||
|         echo $result | ||||
|         # WinBoLL 标签添加成功 | ||||
|     else | ||||
|         echo -e "${0}: addWinBoLLTag $1\n${result}\nAdd WinBoLL tag cancel." | ||||
|         exit 1 # addWinBoLLTag 异常 | ||||
|     fi | ||||
|      | ||||
|     # 添加 GitHub 工作流标签 | ||||
|     if [[ $nAskAddWorkflowsTag -eq 1 ]]; then | ||||
|         # 如果用户选择添加工作流标签 | ||||
|         result=$(addWorkflowsTag $1) | ||||
|         if [[ $? -eq 0 ]]; then | ||||
|             echo $result | ||||
|             # 工作流标签添加成功 | ||||
|         else | ||||
|             echo -e "${0}: addWorkflowsTag $1\n${result}\nAdd workflows tag cancel." | ||||
|             exit 1 # addWorkflowsTag 异常 | ||||
|         fi | ||||
|     fi | ||||
|      | ||||
|     ## 清理更新描述文件内容 | ||||
|     echo "" > $1/app_update_description.txt | ||||
|      | ||||
|     # 设置新版本开发参数配置 | ||||
|     # 提交配置 | ||||
|     git add . | ||||
|     git commit -m "<$1>Start New Stage Debug Version." | ||||
|     echo "Push sources to git repositories ..." | ||||
|     # 推送源码到所有仓库 | ||||
|     git push origin && git push origin --tags | ||||
| else | ||||
|     echo -e "${0}: checkGitSources\n${result}\nShell cancel." | ||||
|     exit 1 # checkGitSources 异常 | ||||
| fi | ||||
							
								
								
									
										14
									
								
								.winboll/bashPublishLIBAddTag.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,14 @@ | ||||
| #!/usr/bin/bash | ||||
|  | ||||
| # 检查是否指定了将要发布的类库名称 | ||||
| # 使用 `-z` 命令检查变量是否为空 | ||||
| if [ -z "$1" ]; then | ||||
|     echo "No Library name specified : $0" | ||||
|     exit 2 | ||||
| fi | ||||
|  | ||||
| ## 正式发布使用 | ||||
| git pull && bash gradlew :$1:publishReleasePublicationToWinBoLLReleaseRepository && bash .winboll/bashCommitLibReleaseBuildFlagInfo.sh $1 | ||||
|  | ||||
| ## 调试使用 | ||||
| #bash gradlew :$1:publishSnapshotWinBoLLPublicationToWinBoLLSnapshotRepository && bash .winboll/bashCommitLibReleaseBuildFlagInfo.sh $1 | ||||
							
								
								
									
										255
									
								
								.winboll/winboll_app_build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,255 @@ | ||||
| // WinBoLL 应用签名配置 | ||||
| // | ||||
|  | ||||
| android { | ||||
|     // 读取秘钥配置文件 | ||||
|     // | ||||
|     def keyProps = new Properties() | ||||
|     def keyPropsFile = rootProject.file("${keyPropsFilePath}") | ||||
|     //println 'Test keystore path' | ||||
|     //println 'KeyProsFile :' + Boolean.toString(keyPropsFile.exists()) | ||||
|     //assert(false) | ||||
|     assert(keyPropsFile.exists()) | ||||
|     keyProps.load(new FileInputStream(keyPropsFile)) | ||||
|      | ||||
|     // 配置签名 | ||||
|     signingConfigs { | ||||
|         winboll { | ||||
|             assert(keyProps['keyAlias'] != null && keyProps['keyPassword'] != null && keyProps['storeFile'] != null && keyProps['storePassword'] != null) | ||||
|             keyAlias keyProps['keyAlias'] | ||||
|             keyPassword keyProps['keyPassword'] | ||||
|             storeFile keyProps['storeFile'] ? file(keyProps['storeFile']) : null | ||||
|             storePassword keyProps['storePassword'] | ||||
|         } | ||||
|     } | ||||
|     buildTypes { | ||||
|         release { | ||||
|             signingConfig signingConfigs.winboll | ||||
|         } | ||||
|         debug { | ||||
|             signingConfig signingConfigs.winboll | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     flavorDimensions "WinBoLLApp" | ||||
|     productFlavors { | ||||
|         beta { | ||||
|             // 检查编译标志位配置 | ||||
|             assert (winbollBuildProps['buildCount'] != null) | ||||
|             dimension "WinBoLLApp" | ||||
|             applicationIdSuffix ".beta" | ||||
|             LocalDateTime localDateTimeNow = LocalDateTime.now(ZoneId.of("Asia/Shanghai")); | ||||
|             versionNameSuffix "-beta" + winbollBuildProps['buildCount'] + "_" + localDateTimeNow.format('mmss') | ||||
|         } | ||||
|         stage { | ||||
|             dimension "WinBoLLApp" | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 应用包输出配置 | ||||
|     // | ||||
|     android.applicationVariants.all { variant -> | ||||
|         // | ||||
|         // GitHub 应用包输出配置 | ||||
|         // 1. 配置 Beta Release 版应用包输出 | ||||
|         // 注意 :GitHub 打包使用 android.yml 的 "bash ./gradlew assembleBetaRelease" 命令 | ||||
|         // | ||||
|         if(variant.flavorName == "beta" && variant.buildType.name == "release") { | ||||
|             /* 后期管理预留代码 */ | ||||
|             /* 暂时没有需要的 GitHub 应用包输出配置 */ | ||||
|             /* GitHub 部分代码忽略 */ | ||||
|         } | ||||
|          | ||||
|         // | ||||
|         // WinBoLL 应用包输出配置 | ||||
|         // 1. 配置 Stage Release 版应用包输出 | ||||
|         // 2. 配置 Beta Debug 版应用包输出 | ||||
| 	    // | ||||
|         if((variant.flavorName == "beta" && variant.buildType.name == "debug") | ||||
|         || (variant.flavorName == "stage" && variant.buildType.name == "debug") | ||||
|         || (variant.flavorName == "stage" && variant.buildType.name == "release")) { | ||||
|             println "Project root directory: " + project.rootDir.toString() | ||||
|             println "Project root directory name : " + project.rootDir.name | ||||
|             def outputPath="${project.projectDir.absolutePath}/build/outputs/apk/${variant.buildType.name}" | ||||
|             //def outputFileName="${rootProject.name}_${versionName}.apk" | ||||
|             def outputFileName=project.rootDir.name + "_${versionName}.apk" | ||||
|              | ||||
|             // 创建 WinBoLL Studio 发布接口文件夹 | ||||
|             File fWinBoLLStudioDir = file("/sdcard/WinBoLLStudio/APKs"); | ||||
|             if(!fWinBoLLStudioDir.exists()) { | ||||
|                 //fWinBoLLStudioDir.mkdirs(); | ||||
|                 // 如果没有发布接口文件就不用进行APK发布和源码管理操作 | ||||
|                 // 当前编译环境不是 WinBoLL 主机, 以下将忽略APK发布和源码管理操作。 | ||||
|                 println 'The current compilation environment is not in WinBoLL host, and the following APK publishing and source management operations will be ignore.' | ||||
|             } else { | ||||
|                 /// WINBOLL 主机的 APK 发布和源码管理操作 /// | ||||
|                 variant.getAssembleProvider().get().doFirst { | ||||
|                     /* 后期管理预留代码 */ | ||||
|                 } //doFirst { | ||||
|                  | ||||
|                 // 编译输出后处理文件部分 | ||||
|                 // | ||||
|                 variant.getAssembleProvider().get().doLast { | ||||
|                         variant.outputs.forEach{ file-> | ||||
|                             // 如果正在调试,就拷贝到 WinBoLL 备份管理文件夹 | ||||
|                             //  | ||||
|                             if(variant.flavorName == "beta"&&variant.buildType.name == "debug"){ | ||||
|                                 //File outBuildBckDir = new File(fWinBoLLStudioDir, "/${rootProject.name}/${variant.buildType.name}") | ||||
|                                 File outBuildBckDir = new File(fWinBoLLStudioDir, "/" + project.rootDir.name + "/${variant.buildType.name}") | ||||
|                                 // 创建目标路径目录 | ||||
|                                 if(!outBuildBckDir.exists()) { | ||||
|                                     outBuildBckDir.mkdirs(); | ||||
|                                     println "Output Folder Created.(WinBoLLStudio) : " + outBuildBckDir.getAbsolutePath() | ||||
|                                 } | ||||
|                                 if(outBuildBckDir.exists()) { | ||||
|                                     copy{ | ||||
|                                         from file.outputFile | ||||
|                                         into outBuildBckDir | ||||
|                                         rename { | ||||
|                                             String fileName -> "${outputFileName}" | ||||
|                                         } | ||||
|                                         println "Output APK (WinBoLLStudio): " + outBuildBckDir.getAbsolutePath() + "/${outputFileName}" | ||||
|                                     } | ||||
|                                     // 检查编译标志位配置 | ||||
|                                     assert (winbollBuildProps['buildCount'] != null) | ||||
|                                     assert (winbollBuildProps['libraryProject'] != null) | ||||
|                                     //构建计数增加 | ||||
|                                     int buildCount = Integer.parseInt(winbollBuildProps['buildCount']) + 1; | ||||
|                                     // 设置编译计数 | ||||
|                                     winbollBuildProps.setProperty("buildCount", Integer.toString(buildCount)); | ||||
|                                      | ||||
|                                     //保存编译标志配置 | ||||
|                                     FileOutputStream fos = new FileOutputStream(winbollBuildPropsFile) | ||||
|                                     winbollBuildProps.store(fos, "${winbollBuildPropsDesc}"); | ||||
|                                     fos.close(); | ||||
|                                      | ||||
|                                     if(winbollBuildProps['libraryProject'] != "") { | ||||
|                                         // 如果应用 build.properties 文件设置了类库模块项目文件名 | ||||
|                                         // 就拷贝一份新的编译标志配置到类库项目文件夹 | ||||
|                                         File libraryProjectBuildPropsFile = new File("$RootProjectDir/" + winbollBuildProps['libraryProject'] + "/build.properties") | ||||
|                                         assert(winbollBuildPropsFile.exists()) | ||||
|                                         assert(libraryProjectBuildPropsFile.exists()) | ||||
|                                         java.nio.file.Path sourceFilePath = winbollBuildPropsFile.toPath(); | ||||
|                                         java.nio.file.Path targetFilePath = libraryProjectBuildPropsFile.toPath(); | ||||
|                                         // 使用copyTo()方法复制文件,如果目标文件存在会被覆盖,可选参数可以选择不覆盖 | ||||
| 	                                    java.nio.file.Files.copy(sourceFilePath, targetFilePath, java.nio.file.StandardCopyOption.REPLACE_EXISTING); | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
|                              | ||||
|                             // 如果正在发布,就拷贝到 WinBoLL 标签管理文件夹 | ||||
|                             // | ||||
|                             if((variant.flavorName == "stage"&&variant.buildType.name == "debug") | ||||
|                                 || (variant.flavorName == "stage"&&variant.buildType.name == "release")){ | ||||
|                                 // 发布 APK 文件 | ||||
|                                 // | ||||
|                                 // 截取版本号的版本字段为短版本名 | ||||
|                                 String szVersionName = "${versionName}" | ||||
|                                 String[] szlistTemp = szVersionName.split("-") | ||||
|                                 String szShortVersionName = szlistTemp[0] | ||||
|                                 //String szCommonTagAPKName = "${rootProject.name}_" + szShortVersionName + ".apk" | ||||
|                                 String szCommonTagAPKName = project.rootDir.name + "_" + szShortVersionName + ".apk" | ||||
|                                 println "CommonTagAPKName is : " + szCommonTagAPKName | ||||
|                                  | ||||
|                                 //File outTagDir = new File(fWinBoLLStudioDir, "/${rootProject.name}/tag/") | ||||
|                                 File outTagDir = new File(fWinBoLLStudioDir, "/" + project.rootDir.name + "/tag/") | ||||
|                                 // 创建目标路径目录 | ||||
|                                 if(!outTagDir.exists()) { | ||||
|                                     outTagDir.mkdirs(); | ||||
|                                     println "Output Folder Created.(Tags) : " + outTagDir.getAbsolutePath() | ||||
|                                 } | ||||
|                                  | ||||
|                                 if(outTagDir.exists()) { | ||||
|                                     File targetAPK = new File(outTagDir, "${szCommonTagAPKName}") | ||||
|                                     if(targetAPK.exists()) { | ||||
|                                         // 标签版本APK文件已经存在,构建拷贝任务停止 | ||||
|                                         assert (!targetAPK.exists()) | ||||
|                                         // 可选择删除并继续输出APK文件 | ||||
|                                         //delete targetAPK | ||||
|                                     } | ||||
|                                     // 复制一个备份 | ||||
|                                     copy{ | ||||
|                                         from file.outputFile | ||||
|                                         into outTagDir | ||||
|                                         rename { | ||||
|                                             String fileName -> "${outputFileName}" | ||||
|                                         } | ||||
|                                         println "Output APK (Tags): "+ outTagDir.getAbsolutePath() + "/${outputFileName}" | ||||
|                                     } | ||||
|                                     // 复制一个并重命名为短版本名 | ||||
|                                     copy{ | ||||
|                                         from file.outputFile | ||||
|                                         into outTagDir | ||||
|                                         rename { | ||||
|                                             String fileName -> "${szCommonTagAPKName}" | ||||
|                                         } | ||||
|                                         println "Output APK (Tags): "+ outTagDir.getAbsolutePath() + "/${szCommonTagAPKName}" | ||||
|                                     } | ||||
|                                     // 检查编译标志位配置 | ||||
|                                     assert (winbollBuildProps['stageCount'] != null) | ||||
|                                     assert (winbollBuildProps['publishVersion'] != null) | ||||
|                                     assert (winbollBuildProps['buildCount'] != null) | ||||
|                                     assert (winbollBuildProps['baseVersion'] != null) | ||||
|                                     assert (winbollBuildProps['baseBetaVersion'] != null) | ||||
|                                     assert (winbollBuildProps['libraryProject'] != null) | ||||
|                                      | ||||
|                                     // 设置类库的默认版本名 | ||||
|                                     winbollBuildProps.setProperty("publishVersion", "${versionName}"); | ||||
|                                     // Stage 发布计数增加 | ||||
|                                     int stageCount = Integer.parseInt(winbollBuildProps['stageCount']) + 1; | ||||
|                                     winbollBuildProps.setProperty("stageCount", Integer.toString(stageCount)); | ||||
|                                     // 设置类库的默认Beta版本名 | ||||
|                                     winbollBuildProps.setProperty("baseBetaVersion", winbollBuildProps['baseVersion'] + "." + Integer.toString(stageCount)); | ||||
|                                     // 构建计数重置 | ||||
|                                     winbollBuildProps.setProperty("buildCount", "0"); | ||||
|                                      | ||||
|                                     //保存编译标志配置 | ||||
|                                     FileOutputStream fos = new FileOutputStream(winbollBuildPropsFile) | ||||
|                                     winbollBuildProps.store(fos, "${winbollBuildPropsDesc}"); | ||||
|                                     fos.close(); | ||||
|                                      | ||||
|                                     if(winbollBuildProps['libraryProject'] != "") { | ||||
|                                         // 如果应用 build.properties 文件设置了类库模块项目文件名 | ||||
|                                         // 就拷贝一份新的编译标志配置到类库项目文件夹 | ||||
|                                         File libraryProjectBuildPropsFile = new File("$RootProjectDir/" + winbollBuildProps['libraryProject'] + "/build.properties") | ||||
|                                         assert(winbollBuildPropsFile.exists()) | ||||
|                                         assert(libraryProjectBuildPropsFile.exists()) | ||||
|                                         java.nio.file.Path sourceFilePath = winbollBuildPropsFile.toPath(); | ||||
|                                         java.nio.file.Path targetFilePath = libraryProjectBuildPropsFile.toPath(); | ||||
|                                         // 使用copyTo()方法复制文件,如果目标文件存在会被覆盖,可选参数可以选择不覆盖 | ||||
|                                         java.nio.file.Files.copy(sourceFilePath, targetFilePath, java.nio.file.StandardCopyOption.REPLACE_EXISTING); | ||||
|                                     } | ||||
|                                      | ||||
|                                     // 提交新的编译标志配置 | ||||
|                                     def resultCommitBuildFlag = exec { | ||||
|                                         commandLine 'bash', '--', "${RootProjectDir}/${bashCommitAppPublishBuildFlagInfoFilePath}", "${RootProjectDir}", "${versionName}", variant.buildType.name , rootProject.name | ||||
|                                     } | ||||
|                                     // 检查bash命令的返回值(假设非零表示失败) | ||||
|                                     assert(resultCommitBuildFlag.getExitValue() == 0) | ||||
|                                 } | ||||
|                             } //  if(variant.buildType.name == "release"){ | ||||
|                              | ||||
|                             // 如果公共目录存在就拷贝到公共目录并重命名为app.apk | ||||
|                             // | ||||
|                             File outCommonDir = new File("/sdcard/AppProjects") | ||||
|                             String commandAPKName = "app.apk" | ||||
|                             if(outCommonDir.exists()) { | ||||
|                                 copy{ | ||||
|                                     from file.outputFile | ||||
|                                     into outCommonDir | ||||
|                                     rename { | ||||
|                                         String fileName -> "${commandAPKName}" | ||||
|                                     } | ||||
|                                     println "Output APK (Common): " + outCommonDir.getAbsolutePath() + "/${commandAPKName}" | ||||
|                                 } | ||||
|                             } | ||||
|                              | ||||
|                          | ||||
|                     } | ||||
| 	            }// End of (variant.getAssembleProvider().get().doLast {) | ||||
|             }/// WINBOLL 主机的 APK 发布和源码管理操作结束 /// | ||||
|         } | ||||
|          | ||||
|     } // End of (android.applicationVariants.all { variant ->) | ||||
| } | ||||
|  | ||||
							
								
								
									
										211
									
								
								.winboll/winboll_lib_build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,211 @@ | ||||
| // 本机和 WinBoLL Maven 仓库传输配置。 | ||||
| // | ||||
|  | ||||
| def getDefaultVersion(){ | ||||
|     // 检查编译标志位配置 | ||||
|     assert (winbollBuildProps['publishVersion'] != null) | ||||
|     // 返回编译版本号 | ||||
|     return winbollBuildProps['publishVersion'] | ||||
| } | ||||
|  | ||||
| def siteUrl = 'https://winboll.cc/?page=studio/details.php&app=${rootProject.name}' // 项目主页 | ||||
| def gitUrl = 'https://gitea.winboll.cc/WinBoLL/${rootProject.name}' // 项目的git地址 | ||||
| def DefaultGroupId = 'cc.winboll.studio' // 类库所有者groupId | ||||
| def DefaultVersion = getDefaultVersion() // 版本号 | ||||
| def DeveloperId='zhangsken' // 开发者账号 | ||||
| def DeveloperName='ZhanGSKen' // 开发者名称 | ||||
| def DeveloperEMail='zhangsken@188.com' // 开发者邮箱地址 | ||||
| def LicenseName='The Apache Software License, Version 2.0' | ||||
| def LicenseUrl='http://www.apache.org/licenses/LICENSE-2.0.txt' | ||||
|  | ||||
| Properties properties = new Properties() | ||||
|  | ||||
| afterEvaluate { | ||||
|     publishing { | ||||
|         repositories { | ||||
|             if(file("${RootProjectDir}/${winbollFilePath}").exists()) { | ||||
|                 properties.load(file("${RootProjectDir}/${winbollFilePath}").newDataInputStream()) | ||||
|                 def NexusUserName = properties.getProperty("Nexus.name") | ||||
|                 def NexusPassword = properties.getProperty("Nexus.password") | ||||
|                 // WinBoLL Release 仓库 | ||||
|                 maven{ | ||||
|                     //仓库的名字和地址 | ||||
|                     name = "WinBoLLRelease" | ||||
|                     url="https://nexus.winboll.cc/repository/maven-releases/" | ||||
|                     // 仓库用户名密码 | ||||
|                     credentials { | ||||
|                         username = NexusUserName | ||||
|                         password = NexusPassword | ||||
|                     } | ||||
|                 } | ||||
|                 // WinBoLL Snapshot 仓库 | ||||
|                 maven{ | ||||
|                     //仓库的名字和地址 | ||||
|                     name = "WinBoLLSnapshot" | ||||
|                     url="https://nexus.winboll.cc/repository/maven-snapshots/" | ||||
|                     // 仓库用户名密码 | ||||
|                     credentials { | ||||
|                         username = NexusUserName | ||||
|                         password = NexusPassword | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         publications { | ||||
|             // Local Maven 仓库传输任务 | ||||
|             // | ||||
|             release(MavenPublication) { | ||||
|                 groupId = DefaultGroupId | ||||
|                 artifactId = project.name | ||||
|                 version = DefaultVersion | ||||
|      | ||||
|                 //from components.java | ||||
|                 // 必须有这个 否则不会上传AAR包 | ||||
|                 afterEvaluate { artifact(tasks.getByName("bundleReleaseAar")) } | ||||
|                 // 上传source,这样使用方可以看到方法注释 | ||||
|                 //artifact generateSourcesJar | ||||
|                 //要上传的aar路径 | ||||
|                 //artifact "$buildDir/outputs/aar/${project.getName()}-release.aar" | ||||
|                 //artifact "$buildDir/outputs/aar/${project.getName()}-debug.aar" | ||||
|                  | ||||
|                 //对pom进行的操作 | ||||
|                 pom.withXml{ | ||||
|                     Node pomNode = asNode() | ||||
|                     pomNode.dependencies.'*'.findAll() { | ||||
|                         //将所有的默认依赖移除 | ||||
|                         //it.parent().remove(it) | ||||
|                     } | ||||
|                 } | ||||
|                 pom { | ||||
|                     name = artifactId | ||||
|                     url = siteUrl | ||||
|                     licenses { | ||||
|                         license { //证书说明 | ||||
|                            name=LicenseName // 开源协议名称 | ||||
|                            url=LicenseUrl // 协议地址 | ||||
|                         } | ||||
|                     } | ||||
|                     developers { | ||||
|                         developer { | ||||
|                             id=DeveloperId // 开发者账号 | ||||
|                             name=DeveloperName // 开发者名称 | ||||
|                             email=DeveloperEMail // 开发者邮箱地址 | ||||
|                         } | ||||
|                     } | ||||
|                     //软件配置管理 | ||||
|                     scm { | ||||
|                         connection=gitUrl | ||||
|                         developerConnection=gitUrl | ||||
|                         url=siteUrl | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             // WinBoLL Maven Release 仓库传输任务 | ||||
|             // | ||||
|             releaseWinBoLL(MavenPublication) { | ||||
|                 // 需要使用的变体,假设有free和pay两个变体,可以选择一个 | ||||
|                 //from components.free | ||||
|                  | ||||
|                 groupId = DefaultGroupId // 文件的groupId | ||||
|                 artifactId = project.name //文件的名字 | ||||
|                 version = DefaultVersion //版本号 | ||||
|      | ||||
|                 //from components.java | ||||
|                 // 必须有这个 否则不会上传AAR包 | ||||
|                 afterEvaluate { artifact(tasks.getByName("bundleReleaseAar")) } | ||||
|                 // 上传source,这样使用方可以看到方法注释 | ||||
|                 //artifact generateSourcesJar | ||||
|                 //要上传的aar路径 | ||||
|                 //artifact "$buildDir/outputs/aar/${project.getName()}-release.aar" | ||||
|                 //artifact "$buildDir/outputs/aar/${project.getName()}-debug.aar" | ||||
|                  | ||||
|                 //对pom进行的操作 | ||||
|                 pom.withXml{ | ||||
|                     Node pomNode = asNode() | ||||
|                     pomNode.dependencies.'*'.findAll() { | ||||
|                         //将所有的默认依赖移除 | ||||
|                         //it.parent().remove(it) | ||||
|                     } | ||||
|                 } | ||||
|                 pom { | ||||
|                     name = artifactId | ||||
|                     url = siteUrl | ||||
|                     licenses { | ||||
|                         license { //证书说明 | ||||
|                            name=LicenseName // 开源协议名称 | ||||
|                            url=LicenseUrl // 协议地址 | ||||
|                         } | ||||
|                     } | ||||
|                     developers { | ||||
|                         developer { | ||||
|                             id=DeveloperId // 开发者账号 | ||||
|                             name=DeveloperName // 开发者名称 | ||||
|                             email=DeveloperEMail // 开发者邮箱地址 | ||||
|                         } | ||||
|                     } | ||||
|                     //软件配置管理 | ||||
|                     scm { | ||||
|                         connection=gitUrl | ||||
|                         developerConnection=gitUrl | ||||
|                         url=siteUrl | ||||
|                     } | ||||
|                 } | ||||
|                  | ||||
|             } // 创建名为 release 的任务结束 | ||||
|              | ||||
|             // WinBoLL Maven Snapshot 仓库传输任务 | ||||
|             // | ||||
|             snapshotWinBoLL(MavenPublication) { | ||||
|                 // 需要使用的变体,假设有free和pay两个变体,可以选择一个 | ||||
|                 //from components.free | ||||
|                  | ||||
|                 groupId = DefaultGroupId // 文件的groupId | ||||
|                 artifactId = project.name //文件的名字 | ||||
|                 version = DefaultVersion + "-SNAPSHOT" //版本号 | ||||
|      | ||||
|                 //from components.java | ||||
|                 // 必须有这个 否则不会上传AAR包 | ||||
|                 afterEvaluate { artifact(tasks.getByName("bundleReleaseAar")) } | ||||
|                 // 上传source,这样使用方可以看到方法注释 | ||||
|                 //artifact generateSourcesJar | ||||
|                 //要上传的aar路径 | ||||
|                 //artifact "$buildDir/outputs/aar/${project.getName()}-release.aar" | ||||
|                 //artifact "$buildDir/outputs/aar/${project.getName()}-debug.aar" | ||||
|                  | ||||
|                 //对pom进行的操作 | ||||
|                 pom.withXml{ | ||||
|                     Node pomNode = asNode() | ||||
|                     pomNode.dependencies.'*'.findAll() { | ||||
|                         //将所有的默认依赖移除 | ||||
|                         //it.parent().remove(it) | ||||
|                     } | ||||
|                 } | ||||
|                 pom { | ||||
|                     name = artifactId | ||||
|                     url = siteUrl | ||||
|                     licenses { | ||||
|                         license { //证书说明 | ||||
|                            name=LicenseName // 开源协议名称 | ||||
|                            url=LicenseUrl // 协议地址 | ||||
|                         } | ||||
|                     } | ||||
|                     developers { | ||||
|                         developer { | ||||
|                             id=DeveloperId // 开发者账号 | ||||
|                             name=DeveloperName // 开发者名称 | ||||
|                             email=DeveloperEMail // 开发者邮箱地址 | ||||
|                         } | ||||
|                     } | ||||
|                     //软件配置管理 | ||||
|                     scm { | ||||
|                         connection=gitUrl | ||||
|                         developerConnection=gitUrl | ||||
|                         url=siteUrl | ||||
|                     } | ||||
|                 } | ||||
|             } // 创建名为 snapshot 的任务结束 | ||||
|         } | ||||
|          | ||||
|     } | ||||
| } | ||||
							
								
								
									
										50
									
								
								.winboll/winboll_lint_build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,50 @@ | ||||
| android { | ||||
|     lintOptions { | ||||
|         // true--关闭lint报告的分析进度 | ||||
|         //quiet true | ||||
|         // true--错误发生后停止gradle构建 | ||||
|         abortOnError false | ||||
|         // true--只报告error | ||||
|         //ignoreWarnings true | ||||
|         // true--忽略有错误的文件的全/绝对路径(默认是true) | ||||
|         //absolutePaths true | ||||
|         // true--检查所有问题点,包含其他默认关闭项 | ||||
|         checkAllWarnings true | ||||
|         // true--所有warning当做error | ||||
|         //warningsAsErrors true | ||||
|         // 关闭指定问题检查 | ||||
|         //disable 'ExpiredTargetSdkVersion','HardcodedText','UnknownNullness','ButtonStyle','GradleDependency','UnusedResources' | ||||
|         // 打开指定问题检查 | ||||
|         //enable 'RtlHardcoded','RtlCompat', 'RtlEnabled' | ||||
|         // 仅检查指定问题 | ||||
|         //check 'NewApi', 'InlinedApi' | ||||
|         // true--error输出文件不包含源码行号 | ||||
|         //noLines true | ||||
|         // true--显示错误的所有发生位置,不截取 | ||||
|         showAll true | ||||
|         // 回退lint设置(默认规则) | ||||
|         //lintConfig file("default-lint.xml") | ||||
|         // true--生成txt格式报告(默认false) | ||||
|         //textReport true | ||||
|         // 重定向输出;可以是文件或'stdout' | ||||
|         //textOutput 'stdout' | ||||
|         // true--生成XML格式报告 | ||||
|         xmlReport true | ||||
|         // 指定xml报告文档(默认lint-results.xml) | ||||
|         xmlOutput file("${lintXmlReportFilePath}") | ||||
|         // true--生成HTML报告(带问题解释,源码位置,等) | ||||
|         htmlReport true | ||||
|         // html报告可选路径(构建器默认是lint-results.html ) | ||||
|         htmlOutput file("${lintHTMLReportFilePath}") | ||||
|         //  true--所有正式版构建执行规则生成崩溃的lint检查,如果有崩溃问题将停止构建 | ||||
|         checkReleaseBuilds true | ||||
|         // 在发布版本编译时检查(即使不包含lint目标),指定问题的规则生成崩溃 | ||||
|         //fatal 'NewApi', 'InlineApi' | ||||
|         // 指定问题的规则生成错误 | ||||
|         //error 'Wakelock', 'TextViewEdits' | ||||
|         // 指定问题的规则生成警告 | ||||
|         //warning 'ResourceAsColor' | ||||
|         // 忽略指定问题的规则(同关闭检查) | ||||
|         //ignore 'TypographyQuotes' | ||||
|     } | ||||
| } | ||||
							
								
								
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						| @@ -198,4 +198,4 @@ | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
|    limitations under the License. | ||||
							
								
								
									
										135
									
								
								README.md
									
									
									
									
									
								
							
							
						
						| @@ -1,2 +1,135 @@ | ||||
| # OriginMaster | ||||
| ## OriginMaster | ||||
| 【OriginMaster】WinBoLL 源生态计划。正如话,我需要一个 Point, 去撬动成个地球。 | ||||
| ######## | ||||
| ## ☁ ☁ ☁ WinBoLL APP ☁ ☁ ☁ ☁ ☁ ☁   ☁ ☁   ☁  ☁ ☁ ☁ ☁  ☁ ☁ ☁ ☁ ☁ ☁  | ||||
| # ☁    ☁ WinBoLL Studio Android 应用开源项目。☁ ☁   ☁ ☁ ☁ ☁  ☁ ☁ ☁ ☁ ☁  ☁ ☁ ☁  | ||||
| # ☁ ☁ ☁ WinBoLL 网站地址 https://www.winboll.cc/ ☁ ☁ ☁ ☁  ☁ ☁ ☁ ☁ | ||||
|  | ||||
| ## WinBoLL 提问 | ||||
| 同样是 /sdcard 目录,在开发 Android 应用时, | ||||
| 能否实现手机编译与电脑编译的源码同步。 | ||||
| ☁因而 WinBoLL 项目组诞生了。 | ||||
|  | ||||
| ## WinBoLL 项目组研发计划 | ||||
| 致力于把 WinBoLL-APP 应用在手机端 Android 项目开发。 | ||||
| 也在探索 https://gitea.winboll.cc/<WinBoLL 项目组>/APP.git 应用于 WinBoLL-APP APK 分发。 | ||||
| 更想进阶 https://github.com/<WinBoLL 项目组>/APP.git 应用于 WinBoLL-APP Beta APK 分发。 | ||||
|  | ||||
| ## WinBoLL-APP 汗下... | ||||
| #### ☁应用何置如此呢。且观用户云云。 | ||||
|  | ||||
| #### ☁ 正当下 ☁ ### | ||||
| #### ☁ 且容傻家叙说 ☁ WinBoLL-APP 应用场景 | ||||
| ### ☁ WinBoLL 设备资源概述 | ||||
| #### ☁ 1. Raid Disk. | ||||
| 概述:这是一个矩阵存储类设备。 | ||||
| 优点:该设备具有数据容错存储功能, | ||||
|      数据存储具有特长持久性。 | ||||
| 缺点:设备使用能源消耗比较高, | ||||
|      设备存取速度一般。 | ||||
|       | ||||
| #### ☁ 2. Data Disk. | ||||
| 概述:这是一个普通硬盘存储设备 | ||||
| 优点:该设备独立于操作系统, | ||||
|      数据持久性一般, | ||||
|      存取能源消耗小于 Raid Disk。 | ||||
| 缺点:数据存储速度一般,存储能源消耗一般。 | ||||
|  | ||||
| #### ☁ 3. SSD Disk. | ||||
| 概述:这是一个 SSD 硬盘存储设备。 | ||||
| 优点:存取速度快于 Data Disk 与 Raid Disk, | ||||
|      存取能源消耗小于 Data Disk 与 Raid Disk。 | ||||
| 缺点:数据持久性一般, | ||||
|      设备位于操作系统内部文件系统。 | ||||
|      数据持久性与操作系统挂钩。 | ||||
|       | ||||
| #### ☁ 4. WinBoLL 用户资源概述。 | ||||
| 1> /home/<用户名> 位于 WinBoLL 操作系统目录下。 | ||||
| 2> /rdisk/<用户名> 挂载用户 Raid Disk. | ||||
| 3> /data/<用户名> 挂载用户 Data Disk. | ||||
| 4> /sdcard/<用户名> 挂载用户 SSD Disk. | ||||
|  | ||||
| #### ☁ 5. WinBoLL-APP 用户资源概述。 | ||||
| 1> /sdcard 挂载用户手机 SD 存储/storage/emulated/0 | ||||
|  | ||||
| ### ☁ 稍稍歇 ☁ ### | ||||
| ### ☁ 急急停 ☁ WinBoLL 应用前置条件 | ||||
| ☁ WinBoLL 主机建立 1Panel MySQL 应用。 | ||||
| ☁ WinBoLL 主机建立 1Panel Gitea 应用。 | ||||
| ☁ WinBoLL 主机设置 WinBoLL 应用为非登录状态。 | ||||
| ☁ WinBoLL 主机建立 WinBoLL 账户与 WinBoLL 用户组。 | ||||
| ☁ WinBoLL 账户 User ID 为: J。 | ||||
| ☁ WinBoLL 用户组 Group ID 为: Studio。 | ||||
| ☁ WinBoLL 主机 WinBoLL 1Panel Gitea 建立 WinBoLL 工作组。 | ||||
| ☁ WinBoLL 主机 WinBoLL 1Panel Gitea 用户项目 APK 编译输出目录为 /sdcard/WinBoLLStudio/<用户名>/APKs/ | ||||
| ☁ WinBoLL 项目配置文件示例为 "<WinBoLL 项目根目录>/.winboll/winboll.properties-demo"(WinBoLL 项目已设置) | ||||
| ☁ WinBoLL 项目配置文件为 "<WinBoLL 项目根目录>/.winboll/winboll.properties" | ||||
| ☁ WinBoLL 项目配置文件设定为源码提交时忽略。(WinBoLL 项目已设置) | ||||
| ☁ Gradle 项目配置文件示例为 "<WinBoLL 项目根目录>/.winboll/local.properties-demo"(WinBoLL 项目已设置) | ||||
| ☁ Gradle 项目配置文件为 "<WinBoLL 项目根目录>/local.properties"(WinBoLL 项目已设置) | ||||
| ☁ Gradle 项目配置文件设定为源码提交时忽略。(WinBoLL 项目已设置) | ||||
|  | ||||
| ### ☁ 登高处 ☁ WinBoLL 应用需求规划 | ||||
| ☁ WinBoLL 主机建立 WinBoLL 客户端用户数据库为 MySQL winbollclient 数据库。 | ||||
| ☁ WinBoLL 主机设置 WinBoLL 客户端用户信息存储在 winbollclient 数据库中。 | ||||
| ☁ MySQL winbollclient 数据库中 | ||||
|    WinBoLL 客户端用户信息设定为: | ||||
|    <用户名, 验证密码, 验证邮箱, 验证手机, 唯一存储令牌Token, 备用验证邮箱>。 | ||||
| ☁ WinBoLL 项目源码仓库托管在 WinBoLL 1Panel Gitea 目录 /opt/1panel/apps/gitea/gitea/data/git/repositories/studio/app.git中。 | ||||
| ☁ WinBoLL 主机提供 WinBoLL 1Panel Gitea 应用的 WinBoLL 项目源码仓库存取功能。(Gitea 应用已提供) | ||||
| ☁ WinBoLL 主机提供 WinBoLL Gitea 项目仓库存档功能。(Gitea 应用已提供) | ||||
| ☁ 提供 WinBoLL 客户端用户登录功能。(Gitea 应用已提供) | ||||
|  | ||||
| ### ☁ 看远方 ☁ ### | ||||
| ### ☁ 心忧虑 ☁ WinBoLL-APP 应用前置需求 | ||||
| ☁ WinBoLL-APP WinBoLL 项目根目录设定为手机的 /sdcard/WinBoLLStudio/Sources 目录。(需要用户手动建立文件夹) | ||||
| ☁ WinBoLL-APP 具有手机 /sdcard/WinBoLL 目录的存储权限。(需要手机操作系统授权) | ||||
| ☁ WinBoLL-APP WinBoLL 项目仓库源码存储路径为 /sdcard/WinBoLLStudio/Sources/APP.git(需要用户手动建立文件夹) | ||||
| ☁ WinBoLL-APP 项目 APK 编译输出目录为 /sdcard/WinBoLLStudio/APKs/ | ||||
| ☁ WinBoLL-APP 应用签名验证可定制化。(WinBoLL 项目已提供) | ||||
| ☁ WinBoLL-APP 与系列衍生 APP 应用共享 cc.winboll.studio 命名空间资源。(WinBoLL 项目已提供) | ||||
| ☁ WinBoLL-APP 用户客户端信息存储在命名空间为 WinBoLL APP MySQLLite 应用的 winbollappclient 数据库中。 | ||||
| ☁ WinBoLL-APP MySQLLite 应用的 winbollappclient 数据库中,  | ||||
|    WinBoLL 用户客户端信息设定为: | ||||
|    <用户名, 唯一存储令牌Token>。 | ||||
|  | ||||
| ### ☁ 云游四方 ☁ ### | ||||
| ### ☁ 呔! ☁ WinBoLL-APP 应用需求规划 | ||||
| ☁ 如要使用 WinBoLL Android 项目的 Gradle 编译功能,则需要设置以下两个文件夹。 | ||||
| ☁ 1. 则需要建立数据存储目录 /sdcard/WinBoLLStudio/APKs。 | ||||
|    WinBoLL 项目源码编译出来的安装包会拷贝一份到 /sdcard/WinBoLLStudio/APKs 目录下。  | ||||
| ☁ 2. 则需要建立数据存储目录 /sdcard/AppProjects。 | ||||
|    WinBoLL 项目源码编译出来的安装包会拷贝一份并命名 "app.apk" 的安装文件为到 /sdcard/AppProjects 目录下。  | ||||
|  | ||||
|  | ||||
| ### ☁ 吁! ☁ WinBoLL-APP 共享计划前景 | ||||
| ☁ WinBoLL-APP 将会实现 https://winboll.cc/api 访问功能。 | ||||
| ☁ WinBoLL-APP 将会实现手机端 Android 应用的开发与管理功能。 | ||||
|  | ||||
| ## ☁ WinBoLL ☁ WinBoLL 主机忧虑 | ||||
| ☁ WinBoLL 将会提供 gitea.winboll.cc 域名用户注册登录功能。 | ||||
| ☁ WinBoLL 将会提供 WinBoLL-APP 及其衍生应用的 Gitea 仓库管理服务。 | ||||
| ☁ WinBoLL 将会提供 winboll.cc 域名 WinBoLL 项目组注册登录功能。 | ||||
|  | ||||
| # 本项目要实际运用需要注意以下几个步骤: | ||||
| # 在项目根目录下: | ||||
| ## 1. 项目模块编译环境设置(必须),settings.gradle-demo 要复制为 settings.gradle,并取消相应项目模块的注释。 | ||||
| ## 2. 项目 Android SDK 编译环境设置(可选),local.properties-demo 要复制为 local.properties,并按需要设置 Android SDK 目录。 | ||||
| ## 3. 类库型模块编译环境设置(可选),winboll.properties-demo 要复制为 winboll.properties,并按需要设置 WinBoLL Maven 库登录用户信息。 | ||||
|  | ||||
|  | ||||
| # ☆类库型项目编译方法 | ||||
| ## 先编译类库对应的模块测试项目 | ||||
| ### 修改模块测试项目的 build.properties 文件 | ||||
| 设置属性 libraryProject=<类库项目模块文件夹名称> | ||||
| ### 再编译测试项目 | ||||
| $ bash .winboll/bashPublishAPKAddTag.sh <应用项目模块文件夹名称> | ||||
| #### 测试项目编译后,编译器会复制一份 APK 到以下路径:"/sdcard/WinBoLLStudio/APKs/<项目根目录名称>/tag/" 文件夹。 | ||||
| ### 最后编译类库项目 | ||||
| $ bash .winboll/bashPublishLIBAddTag.sh <类库项目模块文件夹名称> | ||||
| #### 类库模块编译命令执行后,编译器会发布到 WinBoLL Nexus Maven 库:Maven 库地址可以参阅根项目目录配置 build.gradle 文件。 | ||||
|               | ||||
| # ☆应用型项目编译方法 | ||||
| ## 直接调用以下命令编译应用型项目 | ||||
| $ bash .winboll/bashPublishAPKAddTag.sh <应用项目模块文件夹名称> | ||||
| #### 应用模块编译命令执行后,编译器会复制一份 APK 到以下路径:"/sdcard/WinBoLLStudio/APKs/<项目根目录名称>/tag/" 文件夹。 | ||||
|   | ||||
							
								
								
									
										1
									
								
								aes/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| /build | ||||
							
								
								
									
										1
									
								
								aes/app_update_description.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
|  | ||||
							
								
								
									
										49
									
								
								aes/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,49 @@ | ||||
| apply plugin: 'com.android.application' | ||||
| apply from: '../.winboll/winboll_app_build.gradle' | ||||
| apply from: '../.winboll/winboll_lint_build.gradle' | ||||
|  | ||||
| def genVersionName(def versionName){ | ||||
|     // 检查编译标志位配置 | ||||
|     assert (winbollBuildProps['stageCount'] != null) | ||||
|     assert (winbollBuildProps['baseVersion'] != null) | ||||
|     // 保存基础版本号 | ||||
|     winbollBuildProps.setProperty("baseVersion", "${versionName}"); | ||||
|     //保存编译标志配置 | ||||
|     FileOutputStream fos = new FileOutputStream(winbollBuildPropsFile) | ||||
|     winbollBuildProps.store(fos, "${winbollBuildPropsDesc}"); | ||||
|     fos.close(); | ||||
|      | ||||
|     // 返回编译版本号 | ||||
|     return "${versionName}." + winbollBuildProps['stageCount'] | ||||
| } | ||||
|  | ||||
| android { | ||||
|     compileSdkVersion 32 | ||||
|     buildToolsVersion "32.0.0" | ||||
|  | ||||
|     defaultConfig { | ||||
|         applicationId "cc.winboll.studio.aes" | ||||
|         minSdkVersion 24 | ||||
|         targetSdkVersion 30 | ||||
|         versionCode 1 | ||||
|         // versionName 更新后需要手动设置  | ||||
|         // 项目模块目录的 build.gradle 文件的 stageCount=0 | ||||
|         // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" | ||||
|         versionName "15.6"  | ||||
|         if(true) { | ||||
|             versionName = genVersionName("${versionName}") | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     buildTypes { | ||||
|         release { | ||||
|             minifyEnabled false | ||||
|             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| dependencies { | ||||
| 	api project(':libaes') | ||||
|     api fileTree(dir: 'libs', include: ['*.jar']) | ||||
| } | ||||
							
								
								
									
										8
									
								
								aes/build.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Wed May 07 11:59:55 GMT 2025 | ||||
| stageCount=1 | ||||
| libraryProject=libaes | ||||
| baseVersion=15.6 | ||||
| publishVersion=15.6.0 | ||||
| buildCount=12 | ||||
| baseBetaVersion=15.6.1 | ||||
							
								
								
									
										17
									
								
								aes/proguard-rules.pro
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,17 @@ | ||||
| # Add project specific ProGuard rules here. | ||||
| # By default, the flags in this file are appended to flags specified | ||||
| # in C:\tools\adt-bundle-windows-x86_64-20131030\sdk/tools/proguard/proguard-android.txt | ||||
| # You can edit the include path and order by changing the proguardFiles | ||||
| # directive in build.gradle. | ||||
| # | ||||
| # For more details, see | ||||
| #   http://developer.android.com/guide/developing/tools/proguard.html | ||||
|  | ||||
| # Add any project specific keep options here: | ||||
|  | ||||
| # 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 *; | ||||
| #} | ||||
							
								
								
									
										12
									
								
								aes/src/beta/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,12 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" > | ||||
|  | ||||
|     <application> | ||||
|  | ||||
|         <!-- Put flavor specific code here --> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
|  | ||||
							
								
								
									
										6
									
								
								aes/src/beta/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|  | ||||
|     <!-- Put flavor specific strings here --> | ||||
|     <string name="app_name">AES+</string> | ||||
| </resources> | ||||
							
								
								
									
										38
									
								
								aes/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,38 @@ | ||||
| <?xml version='1.0' encoding='utf-8'?> | ||||
| <manifest | ||||
|     xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     package="cc.winboll.studio.aes"> | ||||
|  | ||||
|     <application | ||||
|         android:name=".App" | ||||
|         android:allowBackup="true" | ||||
|         android:icon="@drawable/ic_launcher" | ||||
|         android:label="@string/app_name" | ||||
|         android:theme="@style/MyAESTheme" | ||||
|         android:requestLegacyExternalStorage="true" | ||||
|         android:supportsRtl="true" | ||||
|         android:networkSecurityConfig="@xml/network_security_config"> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".MainActivity" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="android.intent.action.MAIN"/> | ||||
|  | ||||
|                 <category android:name="android.intent.category.LAUNCHER"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </activity> | ||||
|  | ||||
|         <meta-data | ||||
|             android:name="android.max_aspect" | ||||
|             android:value="4.0"/> | ||||
|  | ||||
|         <activity android:name=".AboutActivity"/> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
							
								
								
									
										93
									
								
								aes/src/main/java/cc/winboll/studio/aes/AboutActivity.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,93 @@ | ||||
| package cc.winboll.studio.aes; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/03/24 23:52:29 | ||||
|  * @Describe AES应用介绍窗口 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.content.Context; | ||||
| import android.os.Bundle; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.LinearLayout; | ||||
| import androidx.appcompat.app.AppCompatActivity; | ||||
| import androidx.appcompat.widget.Toolbar; | ||||
| import cc.winboll.studio.libaes.winboll.APPInfo; | ||||
| import cc.winboll.studio.libaes.winboll.AboutView; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
|  | ||||
| public class AboutActivity extends AppCompatActivity implements IWinBoLLActivity { | ||||
|  | ||||
|     public static final String TAG = "AboutActivity"; | ||||
|  | ||||
|     Context mContext; | ||||
|     Toolbar mToolbar; | ||||
|      | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         mContext = this; | ||||
|         setContentView(R.layout.activity_about); | ||||
|          | ||||
|         mToolbar = findViewById(R.id.toolbar); | ||||
|         setSupportActionBar(mToolbar); | ||||
|         mToolbar.setSubtitle(TAG); | ||||
|         getSupportActionBar().setDisplayHomeAsUpEnabled(true); | ||||
|          | ||||
|         AboutView aboutView = CreateAboutView(); | ||||
|         // 在 Activity 的 onCreate 或其他生命周期方法中调用 | ||||
| //        LinearLayout layout = new LinearLayout(this); | ||||
| //        layout.setOrientation(LinearLayout.VERTICAL); | ||||
| //        // 创建布局参数(宽度和高度) | ||||
| //        ViewGroup.LayoutParams params = new ViewGroup.LayoutParams( | ||||
| //            ViewGroup.LayoutParams.MATCH_PARENT, | ||||
| //            ViewGroup.LayoutParams.MATCH_PARENT | ||||
| //        ); | ||||
| //        addContentView(aboutView, params); | ||||
|          | ||||
|         LinearLayout layout = findViewById(R.id.aboutviewroot_ll); | ||||
|         // 创建布局参数(宽度和高度) | ||||
|         ViewGroup.LayoutParams params = new ViewGroup.LayoutParams( | ||||
|             ViewGroup.LayoutParams.MATCH_PARENT, | ||||
|             ViewGroup.LayoutParams.MATCH_PARENT | ||||
|         ); | ||||
|         layout.addView(aboutView, params); | ||||
|  | ||||
|         GlobalApplication.getWinBoLLActivityManager().add(this); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         GlobalApplication.getWinBoLLActivityManager().registeRemove(this); | ||||
|     } | ||||
|  | ||||
|     public AboutView CreateAboutView() { | ||||
|         String szBranchName = "aes"; | ||||
|         APPInfo appInfo = new APPInfo(); | ||||
|         appInfo.setAppName("AES"); | ||||
|         appInfo.setAppIcon(cc.winboll.studio.libaes.R.drawable.ic_winboll); | ||||
|         appInfo.setAppDescription("AES Description"); | ||||
|         appInfo.setAppGitName("APP"); | ||||
|         appInfo.setAppGitOwner("Studio"); | ||||
|         appInfo.setAppGitAPPBranch(szBranchName); | ||||
|         appInfo.setAppGitAPPSubProjectFolder(szBranchName); | ||||
|         appInfo.setAppHomePage("https://www.winboll.cc/studio/details.php?app=AES"); | ||||
|         appInfo.setAppAPKName("AES"); | ||||
|         appInfo.setAppAPKFolderName("AES"); | ||||
|         //appInfo.setIsAddDebugTools(false); | ||||
|         appInfo.setIsAddDebugTools(BuildConfig.DEBUG); | ||||
|         return new AboutView(mContext, appInfo); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										31
									
								
								aes/src/main/java/cc/winboll/studio/aes/App.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,31 @@ | ||||
| package cc.winboll.studio.aes; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/06/13 19:03:58 | ||||
|  * @Describe AES应用类 | ||||
|  */ | ||||
| import android.view.Gravity; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import com.hjq.toast.style.WhiteToastStyle; | ||||
|  | ||||
|  | ||||
| public class App extends GlobalApplication { | ||||
|  | ||||
|     public static final String TAG = "App"; | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|  | ||||
|         // 初始化 Toast 框架 | ||||
|         ToastUtils.init(this); | ||||
|         // 设置 Toast 布局样式 | ||||
|         //ToastUtils.setView(R.layout.view_toast); | ||||
|         ToastUtils.setStyle(new WhiteToastStyle()); | ||||
|         ToastUtils.setGravity(Gravity.BOTTOM, 0, 200); | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										197
									
								
								aes/src/main/java/cc/winboll/studio/aes/MainActivity.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,197 @@ | ||||
| package cc.winboll.studio.aes; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/06/13 19:05:52 | ||||
|  * @Describe 应用主窗口 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.widget.AdapterView; | ||||
| import android.widget.Toast; | ||||
| import cc.winboll.studio.aes.R; | ||||
| import cc.winboll.studio.libaes.activitys.DrawerFragmentActivity; | ||||
| import cc.winboll.studio.libaes.beans.DrawerMenuBean; | ||||
| import cc.winboll.studio.libaes.dialogs.LocalFileSelectDialog; | ||||
| import cc.winboll.studio.libaes.dialogs.StoragePathDialog; | ||||
| import cc.winboll.studio.libaes.unittests.SecondaryLibraryActivity; | ||||
| import cc.winboll.studio.libaes.unittests.TestAButtonFragment; | ||||
| import cc.winboll.studio.libaes.unittests.TestASupportToolbarActivity; | ||||
| import cc.winboll.studio.libaes.unittests.TestAToolbarActivity; | ||||
| import cc.winboll.studio.libaes.unittests.TestDrawerFragmentActivity; | ||||
| import cc.winboll.studio.libaes.unittests.TestViewPageFragment; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
| import com.a4455jkjh.colorpicker.ColorPickerDialog; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| public class MainActivity extends DrawerFragmentActivity implements IWinBoLLActivity { | ||||
|  | ||||
|  | ||||
|     public static final String TAG = "MainActivity"; | ||||
|  | ||||
|     TestAButtonFragment mTestAButtonFragment; | ||||
|     TestViewPageFragment mTestViewPageFragment; | ||||
|      | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         if (mTestAButtonFragment == null) { | ||||
|             mTestAButtonFragment = new TestAButtonFragment(); | ||||
|             addFragment(mTestAButtonFragment); | ||||
|         } | ||||
|         showFragment(mTestAButtonFragment); | ||||
|         //setSubtitle(TAG); | ||||
|         //ToastUtils.show("onCreate"); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void initDrawerMenuItemList(ArrayList<DrawerMenuBean> listDrawerMenu) { | ||||
|         super.initDrawerMenuItemList(listDrawerMenu); | ||||
|         LogUtils.d(TAG, "initDrawerMenuItemList"); | ||||
|         //listDrawerMenu.clear(); | ||||
|         // 添加抽屉菜单项 | ||||
|         listDrawerMenu.add(new DrawerMenuBean(R.drawable.ic_launcher, TestAButtonFragment.TAG)); | ||||
|         listDrawerMenu.add(new DrawerMenuBean(R.drawable.ic_launcher, TestViewPageFragment.TAG)); | ||||
|         notifyDrawerMenuDataChanged(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void reinitDrawerMenuItemList(ArrayList<DrawerMenuBean> listDrawerMenu) { | ||||
|         super.reinitDrawerMenuItemList(listDrawerMenu); | ||||
|         LogUtils.d(TAG, "reinitDrawerMenuItemList"); | ||||
|         //listDrawerMenu.clear(); | ||||
|         // 添加抽屉菜单项 | ||||
|         listDrawerMenu.add(new DrawerMenuBean(R.drawable.ic_launcher, TestAButtonFragment.TAG)); | ||||
|         listDrawerMenu.add(new DrawerMenuBean(R.drawable.ic_launcher, TestViewPageFragment.TAG)); | ||||
|         notifyDrawerMenuDataChanged(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public DrawerFragmentActivity.ActivityType initActivityType() { | ||||
|         return DrawerFragmentActivity.ActivityType.Main; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         getMenuInflater().inflate(R.menu.toolbar_library, menu); | ||||
|         if(App.isDebuging()) { | ||||
|             getMenuInflater().inflate(cc.winboll.studio.libapputils.R.menu.toolbar_studio_debug, menu); | ||||
|         } | ||||
|         return super.onCreateOptionsMenu(menu); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onItemClick(AdapterView<?> parent, View view, int position, long id) { | ||||
|         super.onItemClick(parent, view, position, id); | ||||
|         switch (position) { | ||||
|             case 0 : { | ||||
|                     if (mTestAButtonFragment == null) { | ||||
|                         mTestAButtonFragment = new TestAButtonFragment(); | ||||
|                         addFragment(mTestAButtonFragment); | ||||
|                     } | ||||
|                     showFragment(mTestAButtonFragment); | ||||
|                     break; | ||||
|                 } | ||||
|             case 1 : { | ||||
|                     if (mTestViewPageFragment == null) { | ||||
|                         mTestViewPageFragment = new TestViewPageFragment(); | ||||
|                         addFragment(mTestViewPageFragment); | ||||
|                     } | ||||
|                     showFragment(mTestViewPageFragment); | ||||
|                     break; | ||||
|                 } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         int nItemId = item.getItemId(); | ||||
| //        if (item.getItemId() == R.id.item_log) { | ||||
| //            WinBoLLActivityManager.getInstance(this).startWinBoLLActivity(getApplicationContext(), LogActivity.class); | ||||
| //        } else  | ||||
|         if (nItemId == R.id.item_atoast) { | ||||
|             Toast.makeText(getApplication(), "item_testatoast", Toast.LENGTH_SHORT).show(); | ||||
|         } else if (nItemId == R.id.item_atoolbar) { | ||||
|             Intent intent = new Intent(this, TestAToolbarActivity.class); | ||||
|             startActivity(intent); | ||||
|  | ||||
|         } else if (nItemId == R.id.item_asupporttoolbar) { | ||||
|             Intent intent = new Intent(this, TestASupportToolbarActivity.class); | ||||
|             startActivity(intent); | ||||
|  | ||||
|         } else if (nItemId == R.id.item_colordialog) { | ||||
|             ColorPickerDialog dlg = new ColorPickerDialog(this, getResources().getColor(R.color.colorPrimary)); | ||||
|             dlg.setOnColorChangedListener(new com.a4455jkjh.colorpicker.view.OnColorChangedListener() { | ||||
|  | ||||
|                     @Override | ||||
|                     public void beforeColorChanged() { | ||||
|                     } | ||||
|  | ||||
|                     @Override | ||||
|                     public void onColorChanged(int color) { | ||||
|  | ||||
|                     } | ||||
|  | ||||
|                     @Override | ||||
|                     public void afterColorChanged() { | ||||
|                     } | ||||
|  | ||||
|  | ||||
|                 }); | ||||
|             dlg.show(); | ||||
|  | ||||
|         } else if (nItemId ==  R.id.item_dialogstoragepath) { | ||||
|             final StoragePathDialog dialog = new StoragePathDialog(this, 0); | ||||
|             dialog.setOnOKClickListener(new View.OnClickListener() { | ||||
|                     @Override | ||||
|                     public void onClick(View v) { | ||||
|                         dialog.dismiss(); | ||||
|                     } | ||||
|                 }); | ||||
|             dialog.show(); | ||||
|  | ||||
|         } else if (nItemId ==  R.id.item_localfileselectdialog) { | ||||
|             final LocalFileSelectDialog dialog = new LocalFileSelectDialog(this); | ||||
|             dialog.setOnOKClickListener(new LocalFileSelectDialog.OKClickListener() { | ||||
|                     @Override | ||||
|                     public void onOKClick(String sz) { | ||||
|                         Toast.makeText(getApplication(), sz, Toast.LENGTH_SHORT).show(); | ||||
|                         //dialog.dismiss(); | ||||
|                     } | ||||
|                 }); | ||||
|             dialog.open(); | ||||
|  | ||||
|         } else if (nItemId ==  R.id.item_secondarylibraryactivity) { | ||||
|             Intent intent = new Intent(this, SecondaryLibraryActivity.class); | ||||
|             startActivity(intent); | ||||
|         } else if (nItemId ==  R.id.item_drawerfragmentactivity) { | ||||
|             Intent intent = new Intent(this, TestDrawerFragmentActivity.class); | ||||
|             startActivity(intent); | ||||
|         }  | ||||
|         else if (nItemId ==  R.id.item_about) { | ||||
|             Intent intent = new Intent(this, AboutActivity.class); | ||||
|             startActivity(intent); | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
|      | ||||
|      | ||||
| } | ||||
							
								
								
									
										22
									
								
								aes/src/main/res/layout/activity_about.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,22 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
| 	<cc.winboll.studio.libaes.views.ASupportToolbar | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:id="@+id/toolbar"/> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="vertical" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:layout_weight="1.0" | ||||
| 		android:id="@+id/aboutviewroot_ll"/> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
							
								
								
									
										32
									
								
								aes/src/main/res/menu/toolbar_library.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,32 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|     <item | ||||
|         android:id="@+id/item_log" | ||||
|         android:title="LogActivity"/> | ||||
|     <item | ||||
|         android:id="@+id/item_colordialog" | ||||
|         android:title="ColorDialog"/> | ||||
|     <item | ||||
|         android:id="@+id/item_dialogstoragepath" | ||||
|         android:title="StoragePathDialog"/> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/item_localfileselectdialog" | ||||
|         android:title="LocalFileSelectDialog"/> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/item_atoolbar" | ||||
|         android:title="Test AToolbar"/> | ||||
|     <item | ||||
|         android:id="@+id/item_asupporttoolbar" | ||||
|         android:title="Test ASupportToolbar"/> | ||||
|     <item | ||||
|         android:id="@+id/item_atoast" | ||||
|         android:title="Test AToast"/> | ||||
|     <item | ||||
|         android:id="@+id/item_secondarylibraryactivity" | ||||
|         android:title="Test SecondaryLibraryActivity"/> | ||||
|     <item | ||||
|         android:id="@+id/item_drawerfragmentactivity" | ||||
|         android:title="Test DrawerFragmentActivity"/> | ||||
| </menu> | ||||
							
								
								
									
										7
									
								
								aes/src/main/res/values/colors.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,7 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <color name="colorPrimary">#FF00B322</color> | ||||
|     <color name="colorPrimaryDark">#FF005C12</color> | ||||
|     <color name="colorAccent">#FF8DFFA2</color> | ||||
|     <color name="colorText">#FFFFFB8D</color> | ||||
| </resources> | ||||
							
								
								
									
										6
									
								
								aes/src/main/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|  | ||||
|     <string name="app_name">AES</string> | ||||
|  | ||||
| </resources> | ||||
							
								
								
									
										5
									
								
								aes/src/main/res/values/styles.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,5 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <style name="MyAESTheme" parent="AESTheme"> | ||||
|     </style> | ||||
| </resources> | ||||
							
								
								
									
										6
									
								
								aes/src/main/res/xml/network_security_config.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <network-security-config> | ||||
|     <domain-config cleartextTrafficPermitted="true"> | ||||
|         <domain includeSubdomains="true">winboll.cc</domain> | ||||
|     </domain-config> | ||||
| </network-security-config> | ||||
							
								
								
									
										12
									
								
								aes/src/stage/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,12 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" > | ||||
|  | ||||
|     <application> | ||||
|  | ||||
|         <!-- Put flavor specific code here --> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
|  | ||||
							
								
								
									
										6
									
								
								aes/src/stage/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|  | ||||
|     <!-- Put flavor specific strings here --> | ||||
|  | ||||
| </resources> | ||||
							
								
								
									
										1
									
								
								androiddemo/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| /build | ||||
							
								
								
									
										0
									
								
								androiddemo/app_update_description.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										72
									
								
								androiddemo/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,72 @@ | ||||
| apply plugin: 'com.android.application' | ||||
| apply from: '../.winboll/winboll_app_build.gradle' | ||||
| apply from: '../.winboll/winboll_lint_build.gradle' | ||||
|  | ||||
| def genVersionName(def versionName){ | ||||
|     // 检查编译标志位配置 | ||||
|     assert (winbollBuildProps['stageCount'] != null) | ||||
|     assert (winbollBuildProps['baseVersion'] != null) | ||||
|     // 保存基础版本号 | ||||
|     winbollBuildProps.setProperty("baseVersion", "${versionName}"); | ||||
|     //保存编译标志配置 | ||||
|     FileOutputStream fos = new FileOutputStream(winbollBuildPropsFile) | ||||
|     winbollBuildProps.store(fos, "${winbollBuildPropsDesc}"); | ||||
|     fos.close(); | ||||
|      | ||||
|     // 返回编译版本号 | ||||
|     return "${versionName}." + winbollBuildProps['stageCount'] | ||||
| } | ||||
|  | ||||
| android { | ||||
|     compileSdkVersion 32 | ||||
|     buildToolsVersion "32.0.0" | ||||
|  | ||||
|     defaultConfig { | ||||
|         applicationId "cc.winboll.studio.androiddemo" | ||||
|         minSdkVersion 24 | ||||
|         targetSdkVersion 29 | ||||
|         versionCode 1 | ||||
|         // versionName 更新后需要手动设置  | ||||
|         // .winboll/winbollBuildProps.properties 文件的 stageCount=0 | ||||
|         // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" | ||||
|         versionName "15.0" | ||||
|         if(true) { | ||||
|             versionName = genVersionName("${versionName}") | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     buildTypes { | ||||
|         release { | ||||
|             minifyEnabled false | ||||
|             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| dependencies { | ||||
|     api fileTree(dir: 'libs', include: ['*.jar']) | ||||
|      | ||||
|     // Android 类库 | ||||
|     //api 'com.android.support:appcompat-v7:28.0.0' | ||||
|     api('com.android.support:appcompat-v7:28.0.0'){ | ||||
|         //exclude group: "com.android.support", module: "support-vector-drawable" | ||||
|         exclude group: "com.android.support:animated-vector-drawable:28.0.0" | ||||
|     } | ||||
|     // https://mvnrepository.com/artifact/com.android.support/support-compat | ||||
|     api 'com.android.support:support-compat:28.0.0' // 保留原有依赖(可选) | ||||
|     // https://mvnrepository.com/artifact/com.android.support/support-v4 | ||||
|     api 'com.android.support:support-v4:28.0.0' | ||||
|     // https://mvnrepository.com/artifact/com.android.support/support-media-compat | ||||
|     api 'com.android.support:support-media-compat:28.0.0' | ||||
|     // https://mvnrepository.com/artifact/com.android.support/support-core-utils | ||||
|     api 'com.android.support:support-core-utils:28.0.0' | ||||
|     // https://mvnrepository.com/artifact/com.android.support/support-core-ui | ||||
|     api 'com.android.support:support-core-ui:28.0.0' | ||||
|     // https://mvnrepository.com/artifact/com.android.support/support-fragment | ||||
|     api 'com.android.support:support-fragment:28.0.0' | ||||
|     // https://mvnrepository.com/artifact/com.android.support/recyclerview-v7 | ||||
|     api 'com.android.support:recyclerview-v7:28.0.0' | ||||
|      | ||||
|     api 'cc.winboll.studio:libapputils:15.2.2' | ||||
|     api 'cc.winboll.studio:libappbase:15.2.2' | ||||
| } | ||||
							
								
								
									
										8
									
								
								androiddemo/build.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Thu Apr 03 03:17:18 GMT 2025 | ||||
| stageCount=0 | ||||
| libraryProject= | ||||
| baseVersion=15.0 | ||||
| publishVersion=15.0.0 | ||||
| buildCount=21 | ||||
| baseBetaVersion=15.0.1 | ||||
							
								
								
									
										21
									
								
								androiddemo/proguard-rules.pro
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -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 | ||||
							
								
								
									
										12
									
								
								androiddemo/src/beta/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,12 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" > | ||||
|  | ||||
|     <application> | ||||
|  | ||||
|         <!-- Put flavor specific code here --> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
|  | ||||
							
								
								
									
										7
									
								
								androiddemo/src/beta/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,7 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|  | ||||
|  | ||||
|     <string name="app_name">Android Demo +</string> | ||||
|  | ||||
| </resources> | ||||
							
								
								
									
										39
									
								
								androiddemo/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,39 @@ | ||||
| <?xml version='1.0' encoding='utf-8'?> | ||||
| <manifest | ||||
|     xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     package="cc.winboll.studio.androiddemo"> | ||||
|  | ||||
|     <application | ||||
|         tools:replace="android:appComponentFactory" | ||||
|         android:appComponentFactory="android.support.v4.app.CoreComponentFactory" | ||||
|         android:icon="@drawable/ic_launcher" | ||||
|         android:label="@string/app_name" | ||||
|         android:theme="@style/AppTheme" | ||||
|         android:resizeableActivity="true" | ||||
|         android:name=".App"> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".MainActivity" | ||||
|             android:label="@string/app_name" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="android.intent.action.MAIN"/> | ||||
|  | ||||
|                 <category android:name="android.intent.category.LAUNCHER"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </activity> | ||||
|  | ||||
|         <meta-data | ||||
|             android:name="android.max_aspect" | ||||
|             android:value="4.0"/> | ||||
|  | ||||
|         <activity android:name=".GlobalApplication$CrashActivity"/> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
							
								
								
									
										334
									
								
								androiddemo/src/main/java/cc/winboll/studio/androiddemo/App.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,334 @@ | ||||
| package cc.winboll.studio.androiddemo; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.content.ClipData; | ||||
| import android.content.ClipboardManager; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.pm.PackageInfo; | ||||
| import android.content.res.Resources; | ||||
| import android.graphics.Typeface; | ||||
| import android.os.Build; | ||||
| import android.os.Bundle; | ||||
| import android.os.Handler; | ||||
| import android.os.Looper; | ||||
| import android.text.TextUtils; | ||||
| import android.util.Log; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.HorizontalScrollView; | ||||
| import android.widget.ScrollView; | ||||
| import android.widget.TextView; | ||||
| import android.widget.Toast; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import java.io.ByteArrayInputStream; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.Closeable; | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
| import java.lang.Thread.UncaughtExceptionHandler; | ||||
| import java.text.DateFormat; | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.Arrays; | ||||
| import java.util.Date; | ||||
| import java.util.LinkedHashMap; | ||||
| import java.util.concurrent.atomic.AtomicBoolean; | ||||
|  | ||||
| public class App extends GlobalApplication { | ||||
|  | ||||
|     private static Handler MAIN_HANDLER = new Handler(Looper.getMainLooper()); | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         //CrashHandler.getInstance().registerGlobal(this); | ||||
|         //CrashHandler.getInstance().registerPart(this); | ||||
|     } | ||||
|  | ||||
|     public static void write(InputStream input, OutputStream output) throws IOException { | ||||
|         byte[] buf = new byte[1024 * 8]; | ||||
|         int len; | ||||
|         while ((len = input.read(buf)) != -1) { | ||||
|             output.write(buf, 0, len); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void write(File file, byte[] data) throws IOException { | ||||
|         File parent = file.getParentFile(); | ||||
|         if (parent != null && !parent.exists()) parent.mkdirs(); | ||||
|  | ||||
|         ByteArrayInputStream input = new ByteArrayInputStream(data); | ||||
|         FileOutputStream output = new FileOutputStream(file); | ||||
|         try { | ||||
|             write(input, output); | ||||
|         } finally { | ||||
|             closeIO(input, output); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static String toString(InputStream input) throws IOException { | ||||
|         ByteArrayOutputStream output = new ByteArrayOutputStream(); | ||||
|         write(input, output); | ||||
|         try { | ||||
|             return output.toString("UTF-8"); | ||||
|         } finally { | ||||
|             closeIO(input, output); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void closeIO(Closeable... closeables) { | ||||
|         for (Closeable closeable : closeables) { | ||||
|             try { | ||||
|                 if (closeable != null) closeable.close(); | ||||
|             } catch (IOException ignored) {} | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static class CrashHandler { | ||||
|  | ||||
|         public static final UncaughtExceptionHandler DEFAULT_UNCAUGHT_EXCEPTION_HANDLER = Thread.getDefaultUncaughtExceptionHandler(); | ||||
|  | ||||
|         private static CrashHandler sInstance; | ||||
|  | ||||
|         private PartCrashHandler mPartCrashHandler; | ||||
|  | ||||
|         public static CrashHandler getInstance() { | ||||
|             if (sInstance == null) { | ||||
|                 sInstance = new CrashHandler(); | ||||
|             } | ||||
|             return sInstance; | ||||
|         } | ||||
|  | ||||
|         public void registerGlobal(Context context) { | ||||
|             registerGlobal(context, null); | ||||
|         } | ||||
|  | ||||
|         public void registerGlobal(Context context, String crashDir) { | ||||
|             Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandlerImpl(context.getApplicationContext(), crashDir)); | ||||
|         } | ||||
|  | ||||
|         public void unregister() { | ||||
|             Thread.setDefaultUncaughtExceptionHandler(DEFAULT_UNCAUGHT_EXCEPTION_HANDLER); | ||||
|         } | ||||
|  | ||||
|         public void registerPart(Context context) { | ||||
|             unregisterPart(context); | ||||
|             mPartCrashHandler = new PartCrashHandler(context.getApplicationContext()); | ||||
|             MAIN_HANDLER.postAtFrontOfQueue(mPartCrashHandler); | ||||
|         } | ||||
|  | ||||
|         public void unregisterPart(Context context) { | ||||
|             if (mPartCrashHandler != null) { | ||||
|                 mPartCrashHandler.isRunning.set(false); | ||||
|                 mPartCrashHandler = null; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private static class PartCrashHandler implements Runnable { | ||||
|  | ||||
|             private final Context mContext; | ||||
|  | ||||
|             public AtomicBoolean isRunning = new AtomicBoolean(true); | ||||
|  | ||||
|             public PartCrashHandler(Context context) { | ||||
|                 this.mContext = context; | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public void run() { | ||||
|                 while (isRunning.get()) { | ||||
|                     try { | ||||
|                         Looper.loop(); | ||||
|                     } catch (final Throwable e) { | ||||
|                         e.printStackTrace(); | ||||
|                         if (isRunning.get()) { | ||||
|                             MAIN_HANDLER.post(new Runnable(){ | ||||
|  | ||||
|                                     @Override | ||||
|                                     public void run() { | ||||
|                                         Toast.makeText(mContext, e.toString(), Toast.LENGTH_LONG).show(); | ||||
|                                     } | ||||
|                                 }); | ||||
|                         } else { | ||||
|                             if (e instanceof RuntimeException) { | ||||
|                                 throw (RuntimeException)e; | ||||
|                             } else { | ||||
|                                 throw new RuntimeException(e); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private static class UncaughtExceptionHandlerImpl implements UncaughtExceptionHandler { | ||||
|  | ||||
|             private static DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss"); | ||||
|  | ||||
|             private final Context mContext; | ||||
|  | ||||
|             private final File mCrashDir; | ||||
|  | ||||
|             public UncaughtExceptionHandlerImpl(Context context, String crashDir) { | ||||
|                 this.mContext = context; | ||||
|                 this.mCrashDir = TextUtils.isEmpty(crashDir) ? new File(mContext.getExternalCacheDir(), "crash") : new File(crashDir); | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public void uncaughtException(Thread thread, Throwable throwable) { | ||||
|                 try { | ||||
|  | ||||
|                     String log = buildLog(throwable); | ||||
|                     writeLog(log); | ||||
|  | ||||
|                     try { | ||||
|                         Intent intent = new Intent(mContext, CrashActivity.class); | ||||
|                         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|                         intent.putExtra(Intent.EXTRA_TEXT, log); | ||||
|                         mContext.startActivity(intent); | ||||
|                     } catch (Throwable e) { | ||||
|                         e.printStackTrace(); | ||||
|                         writeLog(e.toString()); | ||||
|                     } | ||||
|  | ||||
|                     throwable.printStackTrace(); | ||||
|                     android.os.Process.killProcess(android.os.Process.myPid()); | ||||
|                     System.exit(0); | ||||
|  | ||||
|                 } catch (Throwable e) { | ||||
|                     if (DEFAULT_UNCAUGHT_EXCEPTION_HANDLER != null) DEFAULT_UNCAUGHT_EXCEPTION_HANDLER.uncaughtException(thread, throwable); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             private String buildLog(Throwable throwable) { | ||||
|                 String time = DATE_FORMAT.format(new Date()); | ||||
|  | ||||
|                 String versionName = "unknown"; | ||||
|                 long versionCode = 0; | ||||
|                 try { | ||||
|                     PackageInfo packageInfo = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0); | ||||
|                     versionName = packageInfo.versionName; | ||||
|                     versionCode = Build.VERSION.SDK_INT >= 28 ? packageInfo.getLongVersionCode() : packageInfo.versionCode; | ||||
|                 } catch (Throwable ignored) {} | ||||
|  | ||||
|                 LinkedHashMap<String, String> head = new LinkedHashMap<String, String>(); | ||||
|                 head.put("Time Of Crash", time); | ||||
|                 head.put("Device", String.format("%s, %s", Build.MANUFACTURER, Build.MODEL)); | ||||
|                 head.put("Android Version", String.format("%s (%d)", Build.VERSION.RELEASE, Build.VERSION.SDK_INT)); | ||||
|                 head.put("App Version", String.format("%s (%d)", versionName, versionCode)); | ||||
|                 head.put("Kernel", getKernel()); | ||||
|                 head.put("Support Abis", Build.VERSION.SDK_INT >= 21 && Build.SUPPORTED_ABIS != null ? Arrays.toString(Build.SUPPORTED_ABIS): "unknown"); | ||||
|                 head.put("Fingerprint", Build.FINGERPRINT); | ||||
|  | ||||
|                 StringBuilder builder = new StringBuilder(); | ||||
|  | ||||
|                 for (String key : head.keySet()) { | ||||
|                     if (builder.length() != 0) builder.append("\n"); | ||||
|                     builder.append(key); | ||||
|                     builder.append(" :    "); | ||||
|                     builder.append(head.get(key)); | ||||
|                 } | ||||
|  | ||||
|                 builder.append("\n\n"); | ||||
|                 builder.append(Log.getStackTraceString(throwable)); | ||||
|  | ||||
|                 return builder.toString();  | ||||
|             } | ||||
|  | ||||
|             private void writeLog(String log) { | ||||
|                 String time = DATE_FORMAT.format(new Date()); | ||||
|                 File file = new File(mCrashDir, "crash_" + time + ".txt"); | ||||
|                 try { | ||||
|                     write(file, log.getBytes("UTF-8")); | ||||
|                 } catch (Throwable e) { | ||||
|                     e.printStackTrace(); | ||||
|                 }  | ||||
|             } | ||||
|  | ||||
|             private static String getKernel() { | ||||
|                 try { | ||||
|                     return App.toString(new FileInputStream("/proc/version")).trim(); | ||||
|                 } catch (Throwable e) { | ||||
|                     return e.getMessage(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static final class CrashActivity extends Activity { | ||||
|  | ||||
|         private String mLog; | ||||
|  | ||||
|         @Override | ||||
|         protected void onCreate(Bundle savedInstanceState) { | ||||
|             super.onCreate(savedInstanceState); | ||||
|  | ||||
|             setTheme(android.R.style.Theme_DeviceDefault); | ||||
|             setTitle("App Crash"); | ||||
|  | ||||
|             mLog = getIntent().getStringExtra(Intent.EXTRA_TEXT); | ||||
|  | ||||
|             ScrollView contentView = new ScrollView(this); | ||||
|             contentView.setFillViewport(true); | ||||
|  | ||||
|             HorizontalScrollView horizontalScrollView = new HorizontalScrollView(this); | ||||
|  | ||||
|             TextView textView = new TextView(this); | ||||
|             int padding = dp2px(16); | ||||
|             textView.setPadding(padding, padding, padding, padding); | ||||
|             textView.setText(mLog); | ||||
|             textView.setTextIsSelectable(true); | ||||
|             textView.setTypeface(Typeface.DEFAULT); | ||||
|             textView.setLinksClickable(true); | ||||
|  | ||||
|             horizontalScrollView.addView(textView); | ||||
|             contentView.addView(horizontalScrollView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); | ||||
|  | ||||
|             setContentView(contentView); | ||||
|         } | ||||
|  | ||||
|         private void restart() { | ||||
|             Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName()); | ||||
|             if (intent != null) { | ||||
|                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|                 startActivity(intent); | ||||
|             } | ||||
|             finish(); | ||||
|             android.os.Process.killProcess(android.os.Process.myPid()); | ||||
|             System.exit(0); | ||||
|         } | ||||
|  | ||||
|         private static int dp2px(float dpValue) { | ||||
|             final float scale = Resources.getSystem().getDisplayMetrics().density; | ||||
|             return (int) (dpValue * scale + 0.5f); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public boolean onCreateOptionsMenu(Menu menu) { | ||||
|             menu.add(0, android.R.id.copy, 0, android.R.string.copy) | ||||
|                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); | ||||
|             return super.onCreateOptionsMenu(menu); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public boolean onOptionsItemSelected(MenuItem item) { | ||||
|             switch (item.getItemId()) { | ||||
|                 case android.R.id.copy: | ||||
|                     ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); | ||||
|                     cm.setPrimaryClip(ClipData.newPlainText(getPackageName(), mLog)); | ||||
|                     return true; | ||||
|             } | ||||
|             return super.onOptionsItemSelected(item); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onBackPressed() { | ||||
|             restart(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,25 @@ | ||||
| package cc.winboll.studio.androiddemo; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.os.Bundle; | ||||
| import cc.winboll.studio.libappbase.LogView; | ||||
|  | ||||
| public class MainActivity extends Activity { | ||||
|  | ||||
|     LogView mLogView; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_main); | ||||
|  | ||||
|         mLogView = findViewById(R.id.logview); | ||||
|         mLogView.start(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|         mLogView.start(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								androiddemo/src/main/res/drawable/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 9.0 KiB | 
							
								
								
									
										37
									
								
								androiddemo/src/main/res/layout/activity_main.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,37 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	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:orientation="vertical"> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:gravity="center_vertical|center_horizontal" | ||||
| 		android:layout_weight="1.0"> | ||||
|  | ||||
| 		<TextView | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="Android Demo" | ||||
| 			android:textAppearance="?android:attr/textAppearanceLarge"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:layout_weight="1.0"> | ||||
|  | ||||
| 		<cc.winboll.studio.libappbase.LogView | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="Text" | ||||
| 			android:id="@+id/logview"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
							
								
								
									
										9
									
								
								androiddemo/src/main/res/values-v21/styles.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,9 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <style name="AppTheme" parent="@android:style/Theme.Material.Light.DarkActionBar"> | ||||
|         <item name="android:colorPrimary">@color/colorPrimary</item> | ||||
|         <item name="android:colorPrimaryDark">@color/colorPrimaryDark</item> | ||||
|         <item name="android:colorAccent">@color/colorAccent</item> | ||||
|         <item name="android:navigationBarColor">?android:colorPrimary</item> | ||||
| 	</style> | ||||
| </resources> | ||||
							
								
								
									
										6
									
								
								androiddemo/src/main/res/values/colors.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <color name="colorPrimary">#009688</color> | ||||
|     <color name="colorPrimaryDark">#00796B</color> | ||||
|     <color name="colorAccent">#FF9800</color> | ||||
| </resources> | ||||
							
								
								
									
										4
									
								
								androiddemo/src/main/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,4 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <string name="app_name">Android Demo</string> | ||||
| </resources> | ||||
							
								
								
									
										5
									
								
								androiddemo/src/main/res/values/styles.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,5 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <style name="AppTheme" parent="@android:style/Theme.Holo.Light.DarkActionBar"> | ||||
| 	</style> | ||||
| </resources> | ||||
							
								
								
									
										12
									
								
								androiddemo/src/stage/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,12 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" > | ||||
|  | ||||
|     <application> | ||||
|  | ||||
|         <!-- Put flavor specific code here --> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
|  | ||||
							
								
								
									
										6
									
								
								androiddemo/src/stage/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|  | ||||
|     <!-- Put flavor specific strings here --> | ||||
|  | ||||
| </resources> | ||||
							
								
								
									
										1
									
								
								androidxdemo/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| /build | ||||
							
								
								
									
										0
									
								
								androidxdemo/app_update_description.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										73
									
								
								androidxdemo/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,73 @@ | ||||
| apply plugin: 'com.android.application' | ||||
| apply from: '../.winboll/winboll_app_build.gradle' | ||||
| apply from: '../.winboll/winboll_lint_build.gradle' | ||||
|  | ||||
| def genVersionName(def versionName){ | ||||
|     // 检查编译标志位配置 | ||||
|     assert (winbollBuildProps['stageCount'] != null) | ||||
|     assert (winbollBuildProps['baseVersion'] != null) | ||||
|     // 保存基础版本号 | ||||
|     winbollBuildProps.setProperty("baseVersion", "${versionName}"); | ||||
|     //保存编译标志配置 | ||||
|     FileOutputStream fos = new FileOutputStream(winbollBuildPropsFile) | ||||
|     winbollBuildProps.store(fos, "${winbollBuildPropsDesc}"); | ||||
|     fos.close(); | ||||
|      | ||||
|     // 返回编译版本号 | ||||
|     return "${versionName}." + winbollBuildProps['stageCount'] | ||||
| } | ||||
|  | ||||
| android { | ||||
|     compileSdkVersion 32 | ||||
|     buildToolsVersion "32.0.0" | ||||
|  | ||||
|     defaultConfig { | ||||
|         applicationId "cc.winboll.studio.androidxdemo" | ||||
|         minSdkVersion 24 | ||||
|         targetSdkVersion 29 | ||||
|         versionCode 1 | ||||
|         // versionName 更新后需要手动设置  | ||||
|         // .winboll/winbollBuildProps.properties 文件的 stageCount=0 | ||||
|         // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" | ||||
|         versionName "15.0" | ||||
|         if(true) { | ||||
|             versionName = genVersionName("${versionName}") | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     buildTypes { | ||||
|         release { | ||||
|             minifyEnabled false | ||||
|             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| dependencies { | ||||
|     api fileTree(dir: 'libs', include: ['*.jar']) | ||||
|      | ||||
|     // SSH | ||||
|     api 'com.jcraft:jsch:0.1.55' | ||||
|     // Html 解析 | ||||
|     api 'org.jsoup:jsoup:1.13.1' | ||||
|     // 二维码类库 | ||||
|     api 'com.google.zxing:core:3.4.1' | ||||
|     api 'com.journeyapps:zxing-android-embedded:3.6.0' | ||||
|     // 应用介绍页类库 | ||||
|     api 'io.github.medyo:android-about-page:2.0.0' | ||||
|     // 吐司类库 | ||||
|     api 'com.github.getActivity:ToastUtils:10.5' | ||||
|     // 网络连接类库 | ||||
|     api 'com.squareup.okhttp3:okhttp:4.4.1' | ||||
|     // AndroidX 类库 | ||||
|     api 'androidx.appcompat:appcompat:1.1.0' | ||||
|     api 'com.google.android.material:material:1.4.0' | ||||
|     //api 'androidx.viewpager:viewpager:1.0.0' | ||||
|     //api 'androidx.vectordrawable:vectordrawable:1.1.0' | ||||
|     //api 'androidx.vectordrawable:vectordrawable-animated:1.1.0' | ||||
|     //api 'androidx.fragment:fragment:1.1.0' | ||||
|      | ||||
|     api 'cc.winboll.studio:libaes:15.2.6' | ||||
|     api 'cc.winboll.studio:libapputils:15.2.2' | ||||
|     api 'cc.winboll.studio:libappbase:15.2.2' | ||||
| } | ||||
							
								
								
									
										8
									
								
								androidxdemo/build.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Thu Apr 03 03:15:55 GMT 2025 | ||||
| stageCount=0 | ||||
| libraryProject= | ||||
| baseVersion=15.0 | ||||
| publishVersion=15.0.0 | ||||
| buildCount=18 | ||||
| baseBetaVersion=15.0.1 | ||||
							
								
								
									
										21
									
								
								androidxdemo/proguard-rules.pro
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -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 | ||||
							
								
								
									
										12
									
								
								androidxdemo/src/beta/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,12 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" > | ||||
|  | ||||
|     <application> | ||||
|  | ||||
|         <!-- Put flavor specific code here --> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
|  | ||||
							
								
								
									
										6
									
								
								androidxdemo/src/beta/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|  | ||||
|     <string name="app_name">AndroidX Demo +</string> | ||||
|  | ||||
| </resources> | ||||
							
								
								
									
										37
									
								
								androidxdemo/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,37 @@ | ||||
| <?xml version='1.0' encoding='utf-8'?> | ||||
| <manifest | ||||
|     xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     package="cc.winboll.studio.androidxdemo"> | ||||
|  | ||||
|     <application | ||||
|         android:allowBackup="true" | ||||
|         android:icon="@mipmap/ic_launcher" | ||||
|         android:roundIcon="@mipmap/ic_launcher_round" | ||||
|         android:label="@string/app_name" | ||||
|         android:theme="@style/MyAppTheme" | ||||
|         android:resizeableActivity="true" | ||||
|         android:name=".App"> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".MainActivity" | ||||
|             android:label="@string/app_name"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="android.intent.action.MAIN"/> | ||||
|  | ||||
|                 <category android:name="android.intent.category.LAUNCHER"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </activity> | ||||
|  | ||||
|         <meta-data | ||||
|             android:name="android.max_aspect" | ||||
|             android:value="4.0"/> | ||||
|  | ||||
|         <activity android:name=".GlobalApplication$CrashActivity"/> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
| @@ -0,0 +1,345 @@ | ||||
| package cc.winboll.studio.androidxdemo; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.content.ClipData; | ||||
| import android.content.ClipboardManager; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.pm.PackageInfo; | ||||
| import android.content.res.Resources; | ||||
| import android.graphics.Typeface; | ||||
| import android.os.Build; | ||||
| import android.os.Bundle; | ||||
| import android.os.Handler; | ||||
| import android.os.Looper; | ||||
| import android.text.TextUtils; | ||||
| import android.util.Log; | ||||
| import android.view.Gravity; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.HorizontalScrollView; | ||||
| import android.widget.ScrollView; | ||||
| import android.widget.TextView; | ||||
| import android.widget.Toast; | ||||
| import cc.winboll.studio.androidxdemo.R; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import java.io.ByteArrayInputStream; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.Closeable; | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
| import java.lang.Thread.UncaughtExceptionHandler; | ||||
| import java.text.DateFormat; | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.Arrays; | ||||
| import java.util.Date; | ||||
| import java.util.LinkedHashMap; | ||||
| import java.util.concurrent.atomic.AtomicBoolean; | ||||
|  | ||||
| public class App extends GlobalApplication { | ||||
|  | ||||
|     private static Handler MAIN_HANDLER = new Handler(Looper.getMainLooper()); | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|          | ||||
|         // 初始化 Toast 框架 | ||||
|         ToastUtils.init(this); | ||||
|         // 设置 Toast 布局样式 | ||||
|         ToastUtils.setView(R.layout.view_toast); | ||||
|         //ToastUtils.setStyle(new WhiteToastStyle()); | ||||
|         ToastUtils.setGravity(Gravity.BOTTOM, 0, 200); | ||||
|          | ||||
|         //CrashHandler.getInstance().registerGlobal(this); | ||||
|         //CrashHandler.getInstance().registerPart(this); | ||||
|     } | ||||
|  | ||||
|     public static void write(InputStream input, OutputStream output) throws IOException { | ||||
|         byte[] buf = new byte[1024 * 8]; | ||||
|         int len; | ||||
|         while ((len = input.read(buf)) != -1) { | ||||
|             output.write(buf, 0, len); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void write(File file, byte[] data) throws IOException { | ||||
|         File parent = file.getParentFile(); | ||||
|         if (parent != null && !parent.exists()) parent.mkdirs(); | ||||
|  | ||||
|         ByteArrayInputStream input = new ByteArrayInputStream(data); | ||||
|         FileOutputStream output = new FileOutputStream(file); | ||||
|         try { | ||||
|             write(input, output); | ||||
|         } finally { | ||||
|             closeIO(input, output); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static String toString(InputStream input) throws IOException { | ||||
|         ByteArrayOutputStream output = new ByteArrayOutputStream(); | ||||
|         write(input, output); | ||||
|         try { | ||||
|             return output.toString("UTF-8"); | ||||
|         } finally { | ||||
|             closeIO(input, output); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void closeIO(Closeable... closeables) { | ||||
|         for (Closeable closeable : closeables) { | ||||
|             try { | ||||
|                 if (closeable != null) closeable.close(); | ||||
|             } catch (IOException ignored) {} | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static class CrashHandler { | ||||
|  | ||||
|         public static final UncaughtExceptionHandler DEFAULT_UNCAUGHT_EXCEPTION_HANDLER = Thread.getDefaultUncaughtExceptionHandler(); | ||||
|  | ||||
|         private static CrashHandler sInstance; | ||||
|  | ||||
|         private PartCrashHandler mPartCrashHandler; | ||||
|  | ||||
|         public static CrashHandler getInstance() { | ||||
|             if (sInstance == null) { | ||||
|                 sInstance = new CrashHandler(); | ||||
|             } | ||||
|             return sInstance; | ||||
|         } | ||||
|  | ||||
|         public void registerGlobal(Context context) { | ||||
|             registerGlobal(context, null); | ||||
|         } | ||||
|  | ||||
|         public void registerGlobal(Context context, String crashDir) { | ||||
|             Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandlerImpl(context.getApplicationContext(), crashDir)); | ||||
|         } | ||||
|  | ||||
|         public void unregister() { | ||||
|             Thread.setDefaultUncaughtExceptionHandler(DEFAULT_UNCAUGHT_EXCEPTION_HANDLER); | ||||
|         } | ||||
|  | ||||
|         public void registerPart(Context context) { | ||||
|             unregisterPart(context); | ||||
|             mPartCrashHandler = new PartCrashHandler(context.getApplicationContext()); | ||||
|             MAIN_HANDLER.postAtFrontOfQueue(mPartCrashHandler); | ||||
|         } | ||||
|  | ||||
|         public void unregisterPart(Context context) { | ||||
|             if (mPartCrashHandler != null) { | ||||
|                 mPartCrashHandler.isRunning.set(false); | ||||
|                 mPartCrashHandler = null; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private static class PartCrashHandler implements Runnable { | ||||
|  | ||||
|             private final Context mContext; | ||||
|  | ||||
|             public AtomicBoolean isRunning = new AtomicBoolean(true); | ||||
|  | ||||
|             public PartCrashHandler(Context context) { | ||||
|                 this.mContext = context; | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public void run() { | ||||
|                 while (isRunning.get()) { | ||||
|                     try { | ||||
|                         Looper.loop(); | ||||
|                     } catch (final Throwable e) { | ||||
|                         e.printStackTrace(); | ||||
|                         if (isRunning.get()) { | ||||
|                             MAIN_HANDLER.post(new Runnable(){ | ||||
|  | ||||
|                                     @Override | ||||
|                                     public void run() { | ||||
|                                         Toast.makeText(mContext, e.toString(), Toast.LENGTH_LONG).show(); | ||||
|                                     } | ||||
|                                 }); | ||||
|                         } else { | ||||
|                             if (e instanceof RuntimeException) { | ||||
|                                 throw (RuntimeException)e; | ||||
|                             } else { | ||||
|                                 throw new RuntimeException(e); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private static class UncaughtExceptionHandlerImpl implements UncaughtExceptionHandler { | ||||
|  | ||||
|             private static DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss"); | ||||
|  | ||||
|             private final Context mContext; | ||||
|  | ||||
|             private final File mCrashDir; | ||||
|  | ||||
|             public UncaughtExceptionHandlerImpl(Context context, String crashDir) { | ||||
|                 this.mContext = context; | ||||
|                 this.mCrashDir = TextUtils.isEmpty(crashDir) ? new File(mContext.getExternalCacheDir(), "crash") : new File(crashDir); | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public void uncaughtException(Thread thread, Throwable throwable) { | ||||
|                 try { | ||||
|  | ||||
|                     String log = buildLog(throwable); | ||||
|                     writeLog(log); | ||||
|  | ||||
|                     try { | ||||
|                         Intent intent = new Intent(mContext, CrashActivity.class); | ||||
|                         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|                         intent.putExtra(Intent.EXTRA_TEXT, log); | ||||
|                         mContext.startActivity(intent); | ||||
|                     } catch (Throwable e) { | ||||
|                         e.printStackTrace(); | ||||
|                         writeLog(e.toString()); | ||||
|                     } | ||||
|  | ||||
|                     throwable.printStackTrace(); | ||||
|                     android.os.Process.killProcess(android.os.Process.myPid()); | ||||
|                     System.exit(0); | ||||
|  | ||||
|                 } catch (Throwable e) { | ||||
|                     if (DEFAULT_UNCAUGHT_EXCEPTION_HANDLER != null) DEFAULT_UNCAUGHT_EXCEPTION_HANDLER.uncaughtException(thread, throwable); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             private String buildLog(Throwable throwable) { | ||||
|                 String time = DATE_FORMAT.format(new Date()); | ||||
|  | ||||
|                 String versionName = "unknown"; | ||||
|                 long versionCode = 0; | ||||
|                 try { | ||||
|                     PackageInfo packageInfo = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0); | ||||
|                     versionName = packageInfo.versionName; | ||||
|                     versionCode = Build.VERSION.SDK_INT >= 28 ? packageInfo.getLongVersionCode() : packageInfo.versionCode; | ||||
|                 } catch (Throwable ignored) {} | ||||
|  | ||||
|                 LinkedHashMap<String, String> head = new LinkedHashMap<String, String>(); | ||||
|                 head.put("Time Of Crash", time); | ||||
|                 head.put("Device", String.format("%s, %s", Build.MANUFACTURER, Build.MODEL)); | ||||
|                 head.put("Android Version", String.format("%s (%d)", Build.VERSION.RELEASE, Build.VERSION.SDK_INT)); | ||||
|                 head.put("App Version", String.format("%s (%d)", versionName, versionCode)); | ||||
|                 head.put("Kernel", getKernel()); | ||||
|                 head.put("Support Abis", Build.VERSION.SDK_INT >= 21 && Build.SUPPORTED_ABIS != null ? Arrays.toString(Build.SUPPORTED_ABIS): "unknown"); | ||||
|                 head.put("Fingerprint", Build.FINGERPRINT); | ||||
|  | ||||
|                 StringBuilder builder = new StringBuilder(); | ||||
|  | ||||
|                 for (String key : head.keySet()) { | ||||
|                     if (builder.length() != 0) builder.append("\n"); | ||||
|                     builder.append(key); | ||||
|                     builder.append(" :    "); | ||||
|                     builder.append(head.get(key)); | ||||
|                 } | ||||
|  | ||||
|                 builder.append("\n\n"); | ||||
|                 builder.append(Log.getStackTraceString(throwable)); | ||||
|  | ||||
|                 return builder.toString();  | ||||
|             } | ||||
|  | ||||
|             private void writeLog(String log) { | ||||
|                 String time = DATE_FORMAT.format(new Date()); | ||||
|                 File file = new File(mCrashDir, "crash_" + time + ".txt"); | ||||
|                 try { | ||||
|                     write(file, log.getBytes("UTF-8")); | ||||
|                 } catch (Throwable e) { | ||||
|                     e.printStackTrace(); | ||||
|                 }  | ||||
|             } | ||||
|  | ||||
|             private static String getKernel() { | ||||
|                 try { | ||||
|                     return App.toString(new FileInputStream("/proc/version")).trim(); | ||||
|                 } catch (Throwable e) { | ||||
|                     return e.getMessage(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static final class CrashActivity extends Activity { | ||||
|  | ||||
|         private String mLog; | ||||
|  | ||||
|         @Override | ||||
|         protected void onCreate(Bundle savedInstanceState) { | ||||
|             super.onCreate(savedInstanceState); | ||||
|  | ||||
|             setTheme(android.R.style.Theme_DeviceDefault); | ||||
|             setTitle("App Crash"); | ||||
|  | ||||
|             mLog = getIntent().getStringExtra(Intent.EXTRA_TEXT); | ||||
|  | ||||
|             ScrollView contentView = new ScrollView(this); | ||||
|             contentView.setFillViewport(true); | ||||
|  | ||||
|             HorizontalScrollView horizontalScrollView = new HorizontalScrollView(this); | ||||
|  | ||||
|             TextView textView = new TextView(this); | ||||
|             int padding = dp2px(16); | ||||
|             textView.setPadding(padding, padding, padding, padding); | ||||
|             textView.setText(mLog); | ||||
|             textView.setTextIsSelectable(true); | ||||
|             textView.setTypeface(Typeface.DEFAULT); | ||||
|             textView.setLinksClickable(true); | ||||
|  | ||||
|             horizontalScrollView.addView(textView); | ||||
|             contentView.addView(horizontalScrollView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); | ||||
|  | ||||
|             setContentView(contentView); | ||||
|         } | ||||
|  | ||||
|         private void restart() { | ||||
|             Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName()); | ||||
|             if (intent != null) { | ||||
|                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|                 startActivity(intent); | ||||
|             } | ||||
|             finish(); | ||||
|             android.os.Process.killProcess(android.os.Process.myPid()); | ||||
|             System.exit(0); | ||||
|         } | ||||
|  | ||||
|         private static int dp2px(float dpValue) { | ||||
|             final float scale = Resources.getSystem().getDisplayMetrics().density; | ||||
|             return (int) (dpValue * scale + 0.5f); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public boolean onCreateOptionsMenu(Menu menu) { | ||||
|             menu.add(0, android.R.id.copy, 0, android.R.string.copy) | ||||
|                 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); | ||||
|             return super.onCreateOptionsMenu(menu); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public boolean onOptionsItemSelected(MenuItem item) { | ||||
|             switch (item.getItemId()) { | ||||
|                 case android.R.id.copy: | ||||
|                     ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); | ||||
|                     cm.setPrimaryClip(ClipData.newPlainText(getPackageName(), mLog)); | ||||
|                     return true; | ||||
|             } | ||||
|             return super.onOptionsItemSelected(item); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onBackPressed() { | ||||
|             restart(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,31 @@ | ||||
| package cc.winboll.studio.androidxdemo; | ||||
|  | ||||
| import android.os.Bundle; | ||||
| import androidx.appcompat.app.AppCompatActivity; | ||||
| import androidx.appcompat.widget.Toolbar; | ||||
| import cc.winboll.studio.libappbase.LogView; | ||||
| import com.hjq.toast.ToastUtils; | ||||
|  | ||||
| public class MainActivity extends AppCompatActivity { | ||||
|  | ||||
|     LogView mLogView; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_main); | ||||
|  | ||||
| 		Toolbar toolbar=(Toolbar)findViewById(R.id.toolbar); | ||||
| 		setSupportActionBar(toolbar); | ||||
|  | ||||
|         mLogView = findViewById(R.id.logview); | ||||
|          | ||||
|         ToastUtils.show("onCreate"); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|         mLogView.start(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,34 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:aapt="http://schemas.android.com/aapt" | ||||
|     android:width="108dp" | ||||
|     android:height="108dp" | ||||
|     android:viewportHeight="108" | ||||
|     android:viewportWidth="108"> | ||||
|     <path | ||||
|         android:fillType="evenOdd" | ||||
|         android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z" | ||||
|         android:strokeColor="#00000000" | ||||
|         android:strokeWidth="1"> | ||||
|         <aapt:attr name="android:fillColor"> | ||||
|             <gradient | ||||
|                 android:endX="78.5885" | ||||
|                 android:endY="90.9159" | ||||
|                 android:startX="48.7653" | ||||
|                 android:startY="61.0927" | ||||
|                 android:type="linear"> | ||||
|                 <item | ||||
|                     android:color="#44000000" | ||||
|                     android:offset="0.0" /> | ||||
|                 <item | ||||
|                     android:color="#00000000" | ||||
|                     android:offset="1.0" /> | ||||
|             </gradient> | ||||
|         </aapt:attr> | ||||
|     </path> | ||||
|     <path | ||||
|         android:fillColor="#FFFFFF" | ||||
|         android:fillType="nonZero" | ||||
|         android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z" | ||||
|         android:strokeColor="#00000000" | ||||
|         android:strokeWidth="1" /> | ||||
| </vector> | ||||
							
								
								
									
										170
									
								
								androidxdemo/src/main/res/drawable/ic_launcher_background.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,170 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="108dp" | ||||
|     android:height="108dp" | ||||
|     android:viewportHeight="108" | ||||
|     android:viewportWidth="108"> | ||||
|     <path | ||||
|         android:fillColor="#26A69A" | ||||
|         android:pathData="M0,0h108v108h-108z" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M9,0L9,108" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,0L19,108" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M29,0L29,108" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M39,0L39,108" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M49,0L49,108" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M59,0L59,108" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M69,0L69,108" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M79,0L79,108" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M89,0L89,108" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M99,0L99,108" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,9L108,9" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,19L108,19" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,29L108,29" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,39L108,39" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,49L108,49" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,59L108,59" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,69L108,69" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,79L108,79" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,89L108,89" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,99L108,99" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,29L89,29" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,39L89,39" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,49L89,49" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,59L89,59" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,69L89,69" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,79L89,79" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M29,19L29,89" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M39,19L39,89" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M49,19L49,89" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M59,19L59,89" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M69,19L69,89" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M79,19L79,89" | ||||
|         android:strokeColor="#33FFFFFF" | ||||
|         android:strokeWidth="0.8" /> | ||||
| </vector> | ||||
							
								
								
									
										51
									
								
								androidxdemo/src/main/res/layout/activity_main.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,51 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	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:orientation="vertical"> | ||||
|  | ||||
| 	<com.google.android.material.appbar.AppBarLayout | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> | ||||
|  | ||||
| 		<androidx.appcompat.widget.Toolbar | ||||
| 			android:id="@+id/toolbar" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="?attr/actionBarSize" | ||||
| 			app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> | ||||
|  | ||||
| 	</com.google.android.material.appbar.AppBarLayout> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="vertical" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:layout_weight="1.0" | ||||
| 		android:gravity="center_vertical|center_horizontal"> | ||||
|  | ||||
| 		<TextView | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="AndroidX Demo" | ||||
| 			android:textAppearance="?android:attr/textAppearanceLarge"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="vertical" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:layout_weight="1.0"> | ||||
|  | ||||
| 		<cc.winboll.studio.libappbase.LogView | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="match_parent" | ||||
| 			android:id="@+id/logview"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
| @@ -0,0 +1,5 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|     <background android:drawable="@drawable/ic_launcher_background" /> | ||||
|     <foreground android:drawable="@drawable/ic_launcher_foreground" /> | ||||
| </adaptive-icon> | ||||
| @@ -0,0 +1,5 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|     <background android:drawable="@drawable/ic_launcher_background" /> | ||||
|     <foreground android:drawable="@drawable/ic_launcher_foreground" /> | ||||
| </adaptive-icon> | ||||
							
								
								
									
										
											BIN
										
									
								
								androidxdemo/src/main/res/mipmap-hdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								androidxdemo/src/main/res/mipmap-hdpi/ic_launcher_round.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								androidxdemo/src/main/res/mipmap-mdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								androidxdemo/src/main/res/mipmap-mdpi/ic_launcher_round.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								androidxdemo/src/main/res/mipmap-xhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								androidxdemo/src/main/res/mipmap-xhdpi/ic_launcher_round.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								androidxdemo/src/main/res/mipmap-xxhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								androidxdemo/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 10 KiB | 
							
								
								
									
										
											BIN
										
									
								
								androidxdemo/src/main/res/mipmap-xxxhdpi/ic_launcher.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 9.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								androidxdemo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 15 KiB | 
							
								
								
									
										6
									
								
								androidxdemo/src/main/res/values/colors.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <color name="colorPrimary">#009688</color> | ||||
|     <color name="colorPrimaryDark">#00796B</color> | ||||
|     <color name="colorAccent">#FF9800</color> | ||||
| </resources> | ||||
							
								
								
									
										4
									
								
								androidxdemo/src/main/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,4 @@ | ||||
| <resources> | ||||
|     <string name="app_name">AndroidX Demo</string> | ||||
|      | ||||
| </resources> | ||||
							
								
								
									
										11
									
								
								androidxdemo/src/main/res/values/styles.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,11 @@ | ||||
| <resources> | ||||
|  | ||||
|     <!-- Base application theme. --> | ||||
|     <style name="MyAppTheme" parent="Theme.AppCompat.Light.NoActionBar"> | ||||
|         <!-- Customize your theme here. --> | ||||
|         <item name="colorPrimary">@color/colorPrimary</item> | ||||
|         <item name="colorPrimaryDark">@color/colorPrimaryDark</item> | ||||
|         <item name="colorAccent">@color/colorAccent</item> | ||||
|     </style> | ||||
|  | ||||
| </resources> | ||||
							
								
								
									
										12
									
								
								androidxdemo/src/stage/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,12 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" > | ||||
|  | ||||
|     <application> | ||||
|  | ||||
|         <!-- Put flavor specific code here --> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
|  | ||||
							
								
								
									
										6
									
								
								androidxdemo/src/stage/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|  | ||||
|     <!-- Put flavor specific strings here --> | ||||
|  | ||||
| </resources> | ||||
							
								
								
									
										1
									
								
								appbase/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
| /build | ||||
							
								
								
									
										1
									
								
								appbase/app_update_description.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | ||||
|  | ||||
							
								
								
									
										50
									
								
								appbase/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,50 @@ | ||||
| apply plugin: 'com.android.application' | ||||
| apply from: '../.winboll/winboll_app_build.gradle' | ||||
| apply from: '../.winboll/winboll_lint_build.gradle' | ||||
|  | ||||
| def genVersionName(def versionName){ | ||||
|     // 检查编译标志位配置 | ||||
|     assert (winbollBuildProps['stageCount'] != null) | ||||
|     assert (winbollBuildProps['baseVersion'] != null) | ||||
|     // 保存基础版本号 | ||||
|     winbollBuildProps.setProperty("baseVersion", "${versionName}"); | ||||
|     //保存编译标志配置 | ||||
|     FileOutputStream fos = new FileOutputStream(winbollBuildPropsFile) | ||||
|     winbollBuildProps.store(fos, "${winbollBuildPropsDesc}"); | ||||
|     fos.close(); | ||||
|      | ||||
|     // 返回编译版本号 | ||||
|     return "${versionName}." + winbollBuildProps['stageCount'] | ||||
| } | ||||
|  | ||||
| android { | ||||
|      | ||||
|     compileSdkVersion 32 | ||||
|     buildToolsVersion "32.0.0" | ||||
|  | ||||
|     defaultConfig { | ||||
|         applicationId "cc.winboll.studio.appbase" | ||||
|         minSdkVersion 24 | ||||
|         targetSdkVersion 30 | ||||
|         versionCode 1 | ||||
|         // versionName 更新后需要手动设置  | ||||
|         // .winboll/winbollBuildProps.properties 文件的 stageCount=0 | ||||
|         // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" | ||||
|         versionName "15.7" | ||||
|         if(true) { | ||||
|             versionName = genVersionName("${versionName}") | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     buildTypes { | ||||
|         release { | ||||
|             minifyEnabled false | ||||
|             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| dependencies { | ||||
|     api project(':libappbase') | ||||
|     api fileTree(dir: 'libs', include: ['*.jar']) | ||||
| } | ||||
							
								
								
									
										8
									
								
								appbase/build.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Sat May 03 10:32:21 GMT 2025 | ||||
| stageCount=7 | ||||
| libraryProject=libappbase | ||||
| baseVersion=15.7 | ||||
| publishVersion=15.7.6 | ||||
| buildCount=4 | ||||
| baseBetaVersion=15.7.7 | ||||
							
								
								
									
										17
									
								
								appbase/proguard-rules.pro
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,17 @@ | ||||
| # Add project specific ProGuard rules here. | ||||
| # By default, the flags in this file are appended to flags specified | ||||
| # in C:\tools\adt-bundle-windows-x86_64-20131030\sdk/tools/proguard/proguard-android.txt | ||||
| # You can edit the include path and order by changing the proguardFiles | ||||
| # directive in build.gradle. | ||||
| # | ||||
| # For more details, see | ||||
| #   http://developer.android.com/guide/developing/tools/proguard.html | ||||
|  | ||||
| # Add any project specific keep options here: | ||||
|  | ||||
| # 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 *; | ||||
| #} | ||||
							
								
								
									
										12
									
								
								appbase/src/beta/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,12 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" > | ||||
|  | ||||
|     <application> | ||||
|  | ||||
|         <!-- Put flavor specific code here --> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
|  | ||||
							
								
								
									
										6
									
								
								appbase/src/beta/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|  | ||||
|     <string name="app_name">AppBase+</string> | ||||
|  | ||||
| </resources> | ||||
							
								
								
									
										128
									
								
								appbase/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,128 @@ | ||||
| <?xml version='1.0' encoding='utf-8'?> | ||||
| <manifest | ||||
|     xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     package="cc.winboll.studio.appbase"> | ||||
|  | ||||
|     <application | ||||
|         android:name=".App" | ||||
|         android:icon="@drawable/ic_miapp" | ||||
|         android:label="@string/app_name" | ||||
|         android:theme="@style/MyAPPBaseTheme" | ||||
|         android:resizeableActivity="true" | ||||
|         android:process=":App"> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".MainActivity" | ||||
|             android:label="@string/app_name" | ||||
|             android:exported="true" | ||||
|             android:resizeableActivity="true" | ||||
|             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="android.intent.action.MAIN"/> | ||||
|  | ||||
|                 <category android:name="android.intent.category.LAUNCHER"/> | ||||
|  | ||||
|                 <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES"/> | ||||
|  | ||||
|                 <category android:name="android.intent.category.DEFAULT"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </activity> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".activities.NewActivity" | ||||
|             android:label="NewActivity" | ||||
|             android:exported="true" | ||||
|             android:resizeableActivity="true" | ||||
|             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"/> | ||||
|  | ||||
|         <activity android:name=".activities.New2Activity" | ||||
|             android:label="New2Activity" | ||||
|             android:exported="true" | ||||
|             android:resizeableActivity="true" | ||||
|             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"/> | ||||
|  | ||||
|         <service | ||||
|             android:name=".MyTileService" | ||||
|             android:exported="true" | ||||
|             android:label="@string/tileservice_name" | ||||
|             android:icon="@drawable/ic_launcher" | ||||
|             android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="android.service.quicksettings.action.QS_TILE"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </service> | ||||
|  | ||||
|         <service | ||||
|             android:name=".services.MainService" | ||||
|             android:exported="true"/> | ||||
|  | ||||
|         <service | ||||
|             android:name="cc.winboll.studio.appbase.services.TestDemoBindService" | ||||
|             android:exported="true"/> | ||||
|  | ||||
|         <service | ||||
|             android:name="cc.winboll.studio.appbase.services.TestDemoService" | ||||
|             android:exported="true"/> | ||||
|  | ||||
|         <service android:name=".services.AssistantService"/> | ||||
|  | ||||
|         <receiver android:name="cc.winboll.studio.appbase.receivers.MainReceiver" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.appbase.receivers.MainReceiver"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </receiver> | ||||
|  | ||||
|         <receiver | ||||
|             android:name=".widgets.APPNewsWidget" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.appbase.widgets.APPNewsWidget.ACTION_WAKEUP_SERVICE"/> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.appbase.widgets.APPNewsWidget.ACTION_RELOAD_REPORT"/> | ||||
|  | ||||
|                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|             <meta-data | ||||
|                 android:name="android.appwidget.provider" | ||||
|                 android:resource="@xml/widget_provider_info_sos"/> | ||||
|  | ||||
|         </receiver> | ||||
|  | ||||
|         <receiver android:name=".receivers.APPNewsWidgetClickListener" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener.ACTION_PRE"/> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener.ACTION_NEXT"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </receiver> | ||||
|  | ||||
|         <meta-data | ||||
|             android:name="android.max_aspect" | ||||
|             android:value="4.0"/> | ||||
|  | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
							
								
								
									
										27
									
								
								appbase/src/main/java/cc/winboll/studio/appbase/App.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,27 @@ | ||||
| package cc.winboll.studio.appbase; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2025/01/05 09:54:42 | ||||
|  * @Describe APPbase 应用类 | ||||
|  */ | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import android.content.IntentFilter; | ||||
| import cc.winboll.studio.libappbase.sos.SOSCenterServiceReceiver; | ||||
| import cc.winboll.studio.libappbase.sos.SOS; | ||||
|  | ||||
| public class App extends GlobalApplication { | ||||
|  | ||||
|     public static final String TAG = "App"; | ||||
|      | ||||
|     SOSCenterServiceReceiver mSOSCenterServiceReceiver; | ||||
|      | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         mSOSCenterServiceReceiver = new SOSCenterServiceReceiver(); | ||||
|         IntentFilter intentFilter = new IntentFilter(); | ||||
|         intentFilter.addAction(SOS.ACTION_SOS); | ||||
|         registerReceiver(mSOSCenterServiceReceiver, intentFilter); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,183 @@ | ||||
| package cc.winboll.studio.appbase; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.widget.CheckBox; | ||||
| import android.widget.Toolbar; | ||||
| import cc.winboll.studio.appbase.R; | ||||
| import cc.winboll.studio.appbase.activities.NewActivity; | ||||
| import cc.winboll.studio.appbase.services.MainService; | ||||
| import cc.winboll.studio.appbase.services.TestDemoBindService; | ||||
| import cc.winboll.studio.appbase.services.TestDemoService; | ||||
| import cc.winboll.studio.libappbase.CrashHandler; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.GlobalCrashActivity; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.sos.SOS; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils; | ||||
| import cc.winboll.studio.libappbase.widgets.StatusWidget; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
|  | ||||
| public class MainActivity extends WinBoLLActivityBase implements IWinBoLLActivity { | ||||
|  | ||||
|     public static final String TAG = "MainActivity"; | ||||
|  | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     Toolbar mToolbar; | ||||
|     //LogView mLogView; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         ToastUtils.show("onCreate"); | ||||
|         setContentView(R.layout.activity_main); | ||||
|  | ||||
|         mToolbar = findViewById(R.id.toolbar); | ||||
|         setActionBar(mToolbar); | ||||
|  | ||||
|         CheckBox cbIsDebugMode = findViewById(R.id.activitymainCheckBox1); | ||||
|         cbIsDebugMode.setChecked(GlobalApplication.isDebuging()); | ||||
|         //mLogView = findViewById(R.id.activitymainLogView1); | ||||
|  | ||||
| //        if (GlobalApplication.isDebuging()) { | ||||
| //            mLogView.start();  | ||||
| //            ToastUtils.show("LogView start."); | ||||
| //        } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         getMenuInflater().inflate(R.menu.toolbar_main, menu); | ||||
|         getMenuInflater().inflate(R.menu.toolbar_appbase, menu); | ||||
|         return super.onCreateOptionsMenu(menu); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     protected void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         Intent intentAPPWidget = new Intent(this, StatusWidget.class); | ||||
|         intentAPPWidget.setAction(StatusWidget.ACTION_STATUS_UPDATE); | ||||
|         sendBroadcast(intentAPPWidget); | ||||
|     } | ||||
|  | ||||
| 	public void onSwitchDebugMode(View view) { | ||||
|         boolean isDebuging = ((CheckBox)view).isChecked(); | ||||
|         GlobalApplication.setIsDebuging(isDebuging); | ||||
|         GlobalApplication.saveDebugStatus(); | ||||
|     } | ||||
|     | ||||
|     public void onPreviewGlobalCrashActivity(View view) { | ||||
|         Intent intent = new Intent(this, GlobalCrashActivity.class); | ||||
|         intent.putExtra(CrashHandler.EXTRA_CRASH_INFO, "Demo log..."); | ||||
|         startActivity(intent); | ||||
|     } | ||||
|  | ||||
|     public void onStartCenter(View view) { | ||||
|         MainService.startMainService(this); | ||||
|     } | ||||
|  | ||||
|     public void onStopCenter(View view) { | ||||
|         MainService.stopMainService(this); | ||||
|     } | ||||
|  | ||||
|     public void onTestStopMainServiceWithoutSettingEnable(View view) { | ||||
|         LogUtils.d(TAG, "onTestStopMainServiceWithoutSettingEnable"); | ||||
|         stopService(new Intent(this, MainService.class)); | ||||
|     } | ||||
|  | ||||
|     public void onTestUseComponentStartService(View view) { | ||||
|         LogUtils.d(TAG, "onTestUseComponentStartService"); | ||||
|  | ||||
|         // 目标服务的包名和类名 | ||||
|         String packageName = this.getPackageName(); | ||||
|         String serviceClassName = TestDemoService.class.getName(); | ||||
|  | ||||
|         // 构建Intent | ||||
|         Intent intentService = new Intent(); | ||||
|         intentService.setComponent(new ComponentName(packageName, serviceClassName)); | ||||
|  | ||||
|         startService(intentService); | ||||
|     } | ||||
|  | ||||
|     public void onTestDemoServiceSOS(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoService.class); | ||||
|         stopService(intent); | ||||
|         if (App.isDebuging()) { | ||||
|             SOS.sosToAppBaseBeta(this, TestDemoService.class.getName()); | ||||
|         } else { | ||||
|             SOS.sosToAppBase(this, TestDemoService.class.getName()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void onSartTestDemoService(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoService.class); | ||||
|         intent.setAction(TestDemoService.ACTION_ENABLE); | ||||
|         startService(intent); | ||||
|  | ||||
|     } | ||||
|      | ||||
|      | ||||
|  | ||||
|     public void onStopTestDemoService(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoService.class); | ||||
|         intent.setAction(TestDemoService.ACTION_DISABLE); | ||||
|         startService(intent); | ||||
|  | ||||
|         Intent intentStop = new Intent(this, TestDemoService.class); | ||||
|         stopService(intentStop); | ||||
|     } | ||||
|  | ||||
|     public void onStopTestDemoServiceNoSettings(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoService.class); | ||||
|         stopService(intent); | ||||
|     } | ||||
|  | ||||
|     public void onSartTestDemoBindService(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoBindService.class); | ||||
|         intent.setAction(TestDemoBindService.ACTION_ENABLE); | ||||
|         startService(intent); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public void onStopTestDemoBindService(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoBindService.class); | ||||
|         intent.setAction(TestDemoBindService.ACTION_DISABLE); | ||||
|         startService(intent); | ||||
|  | ||||
|         Intent intentStop = new Intent(this, TestDemoBindService.class); | ||||
|         stopService(intentStop); | ||||
|     } | ||||
|  | ||||
|     public void onStopTestDemoBindServiceNoSettings(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoBindService.class); | ||||
|         stopService(intent); | ||||
|     } | ||||
|  | ||||
|     public void onTestOpenNewActivity(View view) { | ||||
|         GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, NewActivity.class); | ||||
|     } | ||||
|  | ||||
|      | ||||
| } | ||||
 ZhanGSKen
					ZhanGSKen