├── .gitignore
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── macore
├── .gitignore
├── bintray.gradle
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── spinytech
│ │ └── macore
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── aidl
│ │ └── com
│ │ │ └── spinytech
│ │ │ └── macore
│ │ │ ├── ILocalRouterAIDL.aidl
│ │ │ └── IWideRouterAIDL.aidl
│ ├── java
│ │ └── com
│ │ │ └── spinytech
│ │ │ └── macore
│ │ │ ├── ErrorAction.java
│ │ │ ├── MaAction.java
│ │ │ ├── MaActionResult.java
│ │ │ ├── MaApplication.java
│ │ │ ├── MaProvider.java
│ │ │ ├── multiprocess
│ │ │ ├── BaseApplicationLogic.java
│ │ │ └── PriorityLogicWrapper.java
│ │ │ ├── router
│ │ │ ├── ConnectServiceWrapper.java
│ │ │ ├── LocalRouter.java
│ │ │ ├── LocalRouterConnectService.java
│ │ │ ├── RouterRequest.java
│ │ │ ├── RouterResponse.java
│ │ │ ├── WideRouter.java
│ │ │ ├── WideRouterApplicationLogic.java
│ │ │ └── WideRouterConnectService.java
│ │ │ └── tools
│ │ │ ├── Logger.java
│ │ │ ├── ProcessUtil.java
│ │ │ └── RouterMessageUtil.java
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── spinytech
│ └── macore
│ └── ExampleUnitTest.java
├── maindemo
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── spinytech
│ │ └── maindemo
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── spinytech
│ │ │ └── maindemo
│ │ │ ├── AsyncAction.java
│ │ │ ├── AttachObjectAction.java
│ │ │ ├── MainActivity.java
│ │ │ ├── MainApplicationLogic.java
│ │ │ ├── MainProvider.java
│ │ │ ├── MainRouterConnectService.java
│ │ │ ├── MyApplication.java
│ │ │ └── SyncAction.java
│ └── res
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── spinytech
│ └── maindemo
│ └── ExampleUnitTest.java
├── musicdemo
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── spinytech
│ │ └── musicdemo
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── spinytech
│ │ │ └── musicdemo
│ │ │ ├── Music.java
│ │ │ ├── MusicApplicationLogic.java
│ │ │ ├── MusicProvider.java
│ │ │ ├── MusicRouterConnectService.java
│ │ │ ├── MusicService.java
│ │ │ ├── PlayAction.java
│ │ │ ├── ShutdownAction.java
│ │ │ └── StopAction.java
│ └── res
│ │ ├── raw
│ │ └── music.mp3
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── spinytech
│ └── musicdemo
│ └── ExampleUnitTest.java
├── picdemo
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── spinytech
│ │ └── picdemo
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ └── messi.png
│ ├── java
│ │ └── com
│ │ │ └── spinytech
│ │ │ └── picdemo
│ │ │ ├── PicAction.java
│ │ │ ├── PicActivity.java
│ │ │ ├── PicApplicationLogic.java
│ │ │ ├── PicProvider.java
│ │ │ └── PicRouterConnectService.java
│ └── res
│ │ ├── layout
│ │ └── activity_pic.xml
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── dimens.xml
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── spinytech
│ └── picdemo
│ └── ExampleUnitTest.java
├── settings.gradle
└── webdemo
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
├── androidTest
└── java
│ └── com
│ └── spinytech
│ └── webdemo
│ └── ExampleInstrumentedTest.java
├── main
├── AndroidManifest.xml
├── assets
│ └── page.html
├── java
│ └── com
│ │ └── spinytech
│ │ └── webdemo
│ │ ├── WebAction.java
│ │ ├── WebActivity.java
│ │ ├── WebApplicationLogic.java
│ │ └── WebProvider.java
└── res
│ ├── layout
│ └── activity_web.xml
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── dimens.xml
│ └── strings.xml
└── test
└── java
└── com
└── spinytech
└── webdemo
└── ExampleUnitTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | .DS_Store
5 | /build
6 | /captures
7 | .externalNativeBuild
8 | /.idea
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ModularizationArchitecture
2 |
3 | ModularizationArchitecture is a routing-based multi-process, component-based architecture on the Android platform: it communicates with different modules and processes by sharing routes without referring to other modules. It is suitable for medium-sized App architecture team collaboration, parallel development, business line decoupling, white-box testing and other scenes.
4 |
5 | ## Getting Start
6 |
7 | [开始使用](http://blog.spinytech.com/2017/02/01/ma_get_start_cn/)
8 |
9 | [Getting Start](http://blog.spinytech.com/2017/02/03/ma_get_start_en/)
10 |
11 | ## Download
12 |
13 | Maven:
14 |
15 | ```xml
16 |
17 | com.spinytech.ma
18 | macore
19 | 0.2.1
20 | pom
21 |
22 | ```
23 |
24 | Gradle:
25 |
26 | ```groovy
27 | compile 'com.spinytech.ma:macore:0.2.1'
28 | ```
29 |
30 | ## ProGuard
31 |
32 | If you are using ProGuard you might need to add the following option:
33 | ```
34 | -dontwarn com.spinytech.**
35 | ```
36 |
37 | ## Other
38 |
39 | [Android架构思考](http://blog.spinytech.com/2016/12/28/android_modularization/)
40 |
41 | ## License
42 |
43 |
44 | Licensed under the Apache License, Version 2.0 (the "License");
45 | you may not use this file except in compliance with the License.
46 | You may obtain a copy of the License at
47 |
48 | http://www.apache.org/licenses/LICENSE-2.0
49 |
50 | Unless required by applicable law or agreed to in writing, software
51 | distributed under the License is distributed on an "AS IS" BASIS,
52 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
53 | See the License for the specific language governing permissions and
54 | limitations under the License.
55 |
56 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.2.3'
9 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
10 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7'
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | jcenter()
19 | }
20 | }
21 |
22 | task clean(type: Delete) {
23 | delete rootProject.buildDir
24 | }
25 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpinyTech/ModularizationArchitecture/7b91fb7cd2c53b46379228cac76fbbda051a26db/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/macore/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/macore/bintray.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.github.dcendents.android-maven'
2 | apply plugin: 'com.jfrog.bintray'
3 | // This is the library version used when deploying the artifact
4 | version = "0.2.1"
5 |
6 | def siteUrl = 'https://github.com/SpinyTech/ModularizationArchitecture' // 项目的主页
7 | def gitUrl = 'https://github.com/SpinyTech/ModularizationArchitecture.git' // Git仓库的url
8 | group = "com.spinytech.ma" // Maven Group ID for the artifact,一般填你唯一的包名
9 | install {
10 | repositories.mavenInstaller {
11 | // This generates POM.xml with proper parameters
12 | pom {
13 | project {
14 | packaging 'aar'
15 | // Add your description here
16 | name 'ModularizationArchitecture'
17 | description 'A modularization architecture for Android program.'
18 | url siteUrl
19 | // Set your license
20 | licenses {
21 | license {
22 | name 'The Apache Software License, Version 2.0'
23 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
24 | }
25 | }
26 | developers {
27 | developer {
28 | id 'spiny' //填写的一些基本信息
29 | name 'spiny'
30 | email 'spiny.tech@gmail.com'
31 | }
32 | }
33 | scm {
34 | connection gitUrl
35 | developerConnection gitUrl
36 | url siteUrl
37 | }
38 | }
39 | }
40 | }
41 | }
42 | task sourcesJar(type: Jar) {
43 | from android.sourceSets.main.java.srcDirs
44 | classifier = 'sources'
45 | }
46 | task javadoc(type: Javadoc) {
47 | source = android.sourceSets.main.java.srcDirs
48 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
49 | }
50 | task javadocJar(type: Jar, dependsOn: javadoc) {
51 | classifier = 'javadoc'
52 | from javadoc.destinationDir
53 | }
54 | artifacts {
55 | archives javadocJar
56 | archives sourcesJar
57 | }
58 | Properties properties = new Properties()
59 | properties.load(project.rootProject.file('local.properties').newDataInputStream())
60 | bintray {
61 | user = properties.getProperty("bintray.user")
62 | key = properties.getProperty("bintray.apikey")
63 | configurations = ['archives']
64 | pkg {
65 | repo = "ModularizationArchitecture"
66 | name = "core" //发布到JCenter上的项目名字
67 | // userOrg = properties.getProperty("bintray.organizationId")
68 | websiteUrl = siteUrl
69 | vcsUrl = gitUrl
70 | licenses = ["Apache-2.0"]
71 | publish = true
72 | }
73 | }
74 | javadoc { //jav doc采用utf-8编码否则会报“GBK的不可映射字符”错误
75 | options{
76 | encoding "UTF-8"
77 | charSet 'UTF-8'
78 | }
79 | }
--------------------------------------------------------------------------------
/macore/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.0"
6 |
7 | defaultConfig {
8 | minSdkVersion 14
9 | targetSdkVersion 25
10 | versionCode 2017011300
11 | versionName "v0.2.1"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | compile fileTree(dir: 'libs', include: ['*.jar'])
26 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
27 | exclude group: 'com.android.support', module: 'support-annotations'
28 | })
29 | testCompile 'junit:junit:4.12'
30 | compile 'com.android.support:appcompat-v7:25.+'
31 | }
32 |
33 | apply from: "bintray.gradle"
34 |
--------------------------------------------------------------------------------
/macore/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/wanglei/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/macore/src/androidTest/java/com/spinytech/macore/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.spinytech.macore.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/macore/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/macore/src/main/aidl/com/spinytech/macore/ILocalRouterAIDL.aidl:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore;
2 |
3 |
4 | interface ILocalRouterAIDL {
5 | boolean checkResponseAsync(String routerRequset);
6 | String route(String routerRequest);
7 | boolean stopWideRouter();
8 | void connectWideRouter();
9 | }
10 |
--------------------------------------------------------------------------------
/macore/src/main/aidl/com/spinytech/macore/IWideRouterAIDL.aidl:
--------------------------------------------------------------------------------
1 | // IRouterAIDL.aidl
2 | package com.spinytech.macore;
3 |
4 | // Declare any non-default types here with import statements
5 |
6 | interface IWideRouterAIDL {
7 | boolean checkResponseAsync(String domain,String routerRequset);
8 | String route(String domain,String routerRequest);
9 | boolean stopRouter(String domain);
10 | }
11 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/ErrorAction.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore;
2 |
3 | import android.content.Context;
4 |
5 | import java.util.HashMap;
6 |
7 | /**
8 | * Created by wanglei on 2016/12/28.
9 | */
10 |
11 | public class ErrorAction extends MaAction {
12 |
13 | private static final String DEFAULT_MESSAGE = "Something was really wrong. Ha ha!";
14 | private int mCode;
15 | private String mMessage;
16 | private boolean mAsync;
17 | public ErrorAction() {
18 | mCode = MaActionResult.CODE_ERROR;
19 | mMessage = DEFAULT_MESSAGE;
20 | mAsync = false;
21 | }
22 |
23 | public ErrorAction(boolean isAsync,int code, String message) {
24 | this.mCode = code;
25 | this.mMessage = message;
26 | this.mAsync = isAsync;
27 | }
28 |
29 | @Override
30 | public boolean isAsync(Context context, HashMap requestData) {
31 | return mAsync;
32 | }
33 |
34 | @Override
35 | public MaActionResult invoke(Context context, HashMap requestData) {
36 | MaActionResult result = new MaActionResult.Builder()
37 | .code(mCode)
38 | .msg(mMessage)
39 | .data(null)
40 | .object(null)
41 | .build();
42 | return result;
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/MaAction.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore;
2 |
3 | import android.content.Context;
4 |
5 | import java.util.HashMap;
6 |
7 | /**
8 | * Created by wanglei on 2016/11/29.
9 | */
10 |
11 | public abstract class MaAction {
12 | public abstract boolean isAsync(Context context, HashMap requestData);
13 | public abstract MaActionResult invoke(Context context, HashMap requestData);
14 | public boolean isAsync(Context context, HashMap requestData,Object object){
15 | return false;
16 | }
17 | public MaActionResult invoke(Context context, HashMap requestData,Object object){
18 | return new MaActionResult.Builder().code(MaActionResult.CODE_NOT_IMPLEMENT).msg("This method has not yet been implemented.").build();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/MaActionResult.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore;
2 |
3 |
4 | import org.json.JSONException;
5 | import org.json.JSONObject;
6 |
7 | /**
8 | * Created by wanglei on 16/6/14.
9 | */
10 | public class MaActionResult {
11 | public static final int CODE_SUCCESS = 0x0000;
12 | public static final int CODE_ERROR = 0x0001;
13 | public static final int CODE_NOT_FOUND = 0X0002;
14 | public static final int CODE_INVALID = 0X0003;
15 | public static final int CODE_ROUTER_NOT_REGISTER = 0X0004;
16 | public static final int CODE_CANNOT_BIND_LOCAL = 0X0005;
17 | public static final int CODE_REMOTE_EXCEPTION = 0X0006;
18 | public static final int CODE_CANNOT_BIND_WIDE = 0X0007;
19 | public static final int CODE_TARGET_IS_WIDE = 0X0008;
20 | public static final int CODE_WIDE_STOPPING = 0X0009;
21 | public static final int CODE_NOT_IMPLEMENT = 0X000a;
22 |
23 | private int code;
24 | private String msg;
25 | private String data;
26 | private Object object;
27 |
28 | private MaActionResult(Builder builder) {
29 | this.code = builder.mCode;
30 | this.msg = builder.mMsg;
31 | this.data = builder.mData;
32 | this.object = builder.mObject;
33 | }
34 |
35 | public Object getObject() {
36 | return object;
37 | }
38 |
39 | public String getData() {
40 | return data;
41 | }
42 |
43 | public int getCode() {
44 | return code;
45 | }
46 |
47 | public String getMsg() {
48 | return msg;
49 | }
50 |
51 | @Override
52 | public String toString() {
53 | JSONObject jsonObject = new JSONObject();
54 | try {
55 | jsonObject.put("code", code);
56 | jsonObject.put("msg", msg);
57 | jsonObject.put("data", data);
58 | } catch (JSONException e) {
59 | e.printStackTrace();
60 | }
61 | return jsonObject.toString();
62 | }
63 |
64 | public static class Builder {
65 | private int mCode;
66 | private String mMsg;
67 | private Object mObject;
68 | private String mData;
69 |
70 | public Builder() {
71 | mCode = CODE_ERROR;
72 | mMsg = "";
73 | mObject = null;
74 | mData = null;
75 | }
76 |
77 | public Builder resultString(String resultString) {
78 | try {
79 | JSONObject jsonObject = new JSONObject(resultString);
80 | this.mCode = jsonObject.getInt("code");
81 | this.mMsg = jsonObject.getString("msg");
82 | this.mData = jsonObject.getString("data");
83 | } catch (JSONException e) {
84 | e.printStackTrace();
85 | }
86 | return this;
87 | }
88 |
89 | public Builder code(int code) {
90 | this.mCode = code;
91 | return this;
92 | }
93 |
94 | public Builder msg(String msg) {
95 | this.mMsg = msg;
96 | return this;
97 | }
98 |
99 | public Builder data(String data) {
100 | this.mData = data;
101 | return this;
102 | }
103 |
104 | public Builder object(Object object) {
105 | this.mObject = object;
106 | return this;
107 | }
108 |
109 | public MaActionResult build() {
110 | return new MaActionResult(this);
111 | }
112 | }
113 |
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/MaApplication.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore;
2 |
3 | import android.app.Application;
4 | import android.content.Intent;
5 | import android.content.res.Configuration;
6 | import android.support.annotation.CallSuper;
7 | import android.support.annotation.NonNull;
8 |
9 | import com.spinytech.macore.multiprocess.BaseApplicationLogic;
10 | import com.spinytech.macore.multiprocess.PriorityLogicWrapper;
11 | import com.spinytech.macore.router.LocalRouter;
12 | import com.spinytech.macore.router.WideRouter;
13 | import com.spinytech.macore.router.WideRouterApplicationLogic;
14 | import com.spinytech.macore.router.WideRouterConnectService;
15 | import com.spinytech.macore.tools.Logger;
16 | import com.spinytech.macore.tools.ProcessUtil;
17 |
18 | import java.util.ArrayList;
19 | import java.util.Collections;
20 | import java.util.HashMap;
21 |
22 | /**
23 | * Created by wanglei on 2016/11/25.
24 | */
25 |
26 | public abstract class MaApplication extends Application {
27 | private static final String TAG = "MaApplication";
28 | private static MaApplication sInstance;
29 | private ArrayList mLogicList;
30 | private HashMap> mLogicClassMap;
31 |
32 | @CallSuper
33 | @Override
34 | public void onCreate() {
35 | super.onCreate();
36 | sInstance = this;
37 | Logger.d(TAG,"Application onCreate start: "+System.currentTimeMillis());
38 | init();
39 | startWideRouter();
40 | initializeLogic();
41 | dispatchLogic();
42 | instantiateLogic();
43 |
44 | // Traverse the application logic.
45 | if (null != mLogicList && mLogicList.size() > 0) {
46 | for (PriorityLogicWrapper priorityLogicWrapper : mLogicList) {
47 | if (null != priorityLogicWrapper && null != priorityLogicWrapper.instance) {
48 | priorityLogicWrapper.instance.onCreate();
49 | }
50 | }
51 | }
52 | Logger.d(TAG,"Application onCreate end: "+System.currentTimeMillis());
53 | }
54 |
55 | private void init() {
56 | LocalRouter.getInstance(this);
57 | mLogicClassMap = new HashMap<>();
58 | }
59 |
60 | protected void startWideRouter() {
61 | if (needMultipleProcess()) {
62 | registerApplicationLogic(WideRouter.PROCESS_NAME, 1000, WideRouterApplicationLogic.class);
63 | Intent intent = new Intent(this, WideRouterConnectService.class);
64 | startService(intent);
65 | }
66 | }
67 |
68 | public abstract void initializeAllProcessRouter();
69 |
70 | protected abstract void initializeLogic();
71 |
72 | public abstract boolean needMultipleProcess();
73 |
74 | protected boolean registerApplicationLogic(String processName, int priority, @NonNull Class extends BaseApplicationLogic> logicClass) {
75 | boolean result = false;
76 | if (null != mLogicClassMap) {
77 | ArrayList tempList = mLogicClassMap.get(processName);
78 | if (null == tempList) {
79 | tempList = new ArrayList<>();
80 | mLogicClassMap.put(processName, tempList);
81 | }
82 | if (tempList.size() > 0) {
83 | for (PriorityLogicWrapper priorityLogicWrapper : tempList) {
84 | if (logicClass.getName().equals(priorityLogicWrapper.logicClass.getName())) {
85 | throw new RuntimeException(logicClass.getName() + " has registered.");
86 | }
87 | }
88 | }
89 | PriorityLogicWrapper priorityLogicWrapper = new PriorityLogicWrapper(priority, logicClass);
90 | tempList.add(priorityLogicWrapper);
91 | }
92 | return result;
93 | }
94 |
95 | private void dispatchLogic() {
96 | if (null != mLogicClassMap) {
97 | mLogicList = mLogicClassMap.get(ProcessUtil.getProcessName(this, ProcessUtil.getMyProcessId()));
98 | }
99 | }
100 |
101 | private void instantiateLogic() {
102 | if (null != mLogicList && mLogicList.size() > 0) {
103 | if (null != mLogicList && mLogicList.size() > 0) {
104 | Collections.sort(mLogicList);
105 | for (PriorityLogicWrapper priorityLogicWrapper : mLogicList) {
106 | if (null != priorityLogicWrapper) {
107 | try {
108 | priorityLogicWrapper.instance = priorityLogicWrapper.logicClass.newInstance();
109 | } catch (InstantiationException e) {
110 | e.printStackTrace();
111 | } catch (IllegalAccessException e) {
112 | e.printStackTrace();
113 | }
114 | if (null != priorityLogicWrapper.instance) {
115 | priorityLogicWrapper.instance.setApplication(this);
116 | }
117 | }
118 | }
119 | }
120 | }
121 | }
122 |
123 | @Override
124 | public void onTerminate() {
125 | super.onTerminate();
126 | if (null != mLogicList && mLogicList.size() > 0) {
127 | for (PriorityLogicWrapper priorityLogicWrapper : mLogicList) {
128 | if (null != priorityLogicWrapper && null != priorityLogicWrapper.instance) {
129 | priorityLogicWrapper.instance.onTerminate();
130 | }
131 | }
132 | }
133 | }
134 |
135 | @Override
136 | public void onLowMemory() {
137 | super.onLowMemory();
138 | if (null != mLogicList && mLogicList.size() > 0) {
139 | for (PriorityLogicWrapper priorityLogicWrapper : mLogicList) {
140 | if (null != priorityLogicWrapper && null != priorityLogicWrapper.instance) {
141 | priorityLogicWrapper.instance.onLowMemory();
142 | }
143 | }
144 | }
145 | }
146 |
147 | @Override
148 | public void onTrimMemory(int level) {
149 | super.onTrimMemory(level);
150 | if (null != mLogicList && mLogicList.size() > 0) {
151 | for (PriorityLogicWrapper priorityLogicWrapper : mLogicList) {
152 | if (null != priorityLogicWrapper && null != priorityLogicWrapper.instance) {
153 | priorityLogicWrapper.instance.onTrimMemory(level);
154 | }
155 | }
156 | }
157 | }
158 |
159 | @Override
160 | public void onConfigurationChanged(Configuration newConfig) {
161 | super.onConfigurationChanged(newConfig);
162 | if (null != mLogicList && mLogicList.size() > 0) {
163 | for (PriorityLogicWrapper priorityLogicWrapper : mLogicList) {
164 | if (null != priorityLogicWrapper && null != priorityLogicWrapper.instance) {
165 | priorityLogicWrapper.instance.onConfigurationChanged(newConfig);
166 | }
167 | }
168 | }
169 | }
170 |
171 | public static MaApplication getMaApplication(){
172 | return sInstance;
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/MaProvider.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore;
2 |
3 | import java.util.HashMap;
4 |
5 | /**
6 | * Created by wanglei on 2016/11/29.
7 | */
8 |
9 | public abstract class MaProvider{
10 | //TODO this field is used for control the provider on and off
11 | private boolean mValid = true;
12 | private HashMap mActions;
13 | public MaProvider(){
14 | mActions = new HashMap<>();
15 | registerActions();
16 | }
17 | protected void registerAction(String actionName,MaAction action){
18 | mActions.put(actionName,action);
19 | }
20 |
21 | public MaAction findAction(String actionName){
22 | return mActions.get(actionName);
23 | }
24 |
25 | public boolean isValid(){
26 | return mValid;
27 | }
28 |
29 | protected abstract void registerActions();
30 | }
31 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/multiprocess/BaseApplicationLogic.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore.multiprocess;
2 |
3 | import android.content.res.Configuration;
4 | import android.support.annotation.NonNull;
5 |
6 | import com.spinytech.macore.MaApplication;
7 |
8 | /**
9 | * Created by wanglei on 2016/11/25.
10 | */
11 |
12 | public class BaseApplicationLogic {
13 | protected MaApplication mApplication;
14 | public BaseApplicationLogic() {
15 | }
16 |
17 | public void setApplication(@NonNull MaApplication application) {
18 | mApplication = application;
19 | }
20 |
21 | public void onCreate() {
22 | }
23 |
24 | public void onTerminate() {
25 | }
26 |
27 | public void onLowMemory() {
28 | }
29 |
30 | public void onTrimMemory(int level) {
31 | }
32 |
33 | public void onConfigurationChanged(Configuration newConfig) {
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/multiprocess/PriorityLogicWrapper.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore.multiprocess;
2 |
3 |
4 | /**
5 | * Created by wanglei on 2016/11/25.
6 | */
7 |
8 | public class PriorityLogicWrapper implements Comparable {
9 |
10 | public int priority = 0;
11 | public Class extends BaseApplicationLogic> logicClass = null;
12 | public BaseApplicationLogic instance;
13 |
14 | public PriorityLogicWrapper(int priority, Class extends BaseApplicationLogic> logicClass) {
15 | this.priority = priority;
16 | this.logicClass = logicClass;
17 | }
18 |
19 | @Override
20 | public int compareTo(PriorityLogicWrapper o) {
21 | return o.priority - this.priority;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/router/ConnectServiceWrapper.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore.router;
2 |
3 | /**
4 | * Created by wanglei on 2016/11/30.
5 | */
6 |
7 | public class ConnectServiceWrapper {
8 | public Class extends LocalRouterConnectService> targetClass = null;
9 |
10 | public ConnectServiceWrapper( Class extends LocalRouterConnectService> logicClass) {
11 | this.targetClass = logicClass;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/router/LocalRouter.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore.router;
2 |
3 | import android.content.ComponentName;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.ServiceConnection;
7 | import android.os.IBinder;
8 | import android.os.RemoteException;
9 | import android.support.annotation.NonNull;
10 |
11 | import com.spinytech.macore.ErrorAction;
12 | import com.spinytech.macore.IWideRouterAIDL;
13 | import com.spinytech.macore.MaAction;
14 | import com.spinytech.macore.MaActionResult;
15 | import com.spinytech.macore.MaApplication;
16 | import com.spinytech.macore.MaProvider;
17 | import com.spinytech.macore.tools.Logger;
18 | import com.spinytech.macore.tools.ProcessUtil;
19 |
20 | import java.util.HashMap;
21 | import java.util.concurrent.Callable;
22 | import java.util.concurrent.ExecutorService;
23 | import java.util.concurrent.Executors;
24 |
25 | import static android.content.Context.BIND_AUTO_CREATE;
26 |
27 | /**
28 | * The Local Router
29 | */
30 |
31 | public class LocalRouter {
32 | private static final String TAG = "LocalRouter";
33 | private String mProcessName = ProcessUtil.UNKNOWN_PROCESS_NAME;
34 | private static LocalRouter sInstance = null;
35 | private HashMap mProviders = null;
36 | private MaApplication mApplication;
37 | private IWideRouterAIDL mWideRouterAIDL;
38 | private static ExecutorService threadPool = null;
39 | private ServiceConnection mServiceConnection = new ServiceConnection() {
40 | @Override
41 | public void onServiceConnected(ComponentName name, IBinder service) {
42 | mWideRouterAIDL = IWideRouterAIDL.Stub.asInterface(service);
43 | }
44 |
45 | @Override
46 | public void onServiceDisconnected(ComponentName name) {
47 | mWideRouterAIDL = null;
48 | }
49 | };
50 |
51 | private LocalRouter(MaApplication context) {
52 | mApplication = context;
53 | mProcessName = ProcessUtil.getProcessName(context, ProcessUtil.getMyProcessId());
54 | mProviders = new HashMap<>();
55 | if (mApplication.needMultipleProcess() && !WideRouter.PROCESS_NAME.equals(mProcessName)) {
56 | connectWideRouter();
57 | }
58 | }
59 |
60 | public static synchronized LocalRouter getInstance(@NonNull MaApplication context) {
61 | if (sInstance == null) {
62 | sInstance = new LocalRouter(context);
63 | }
64 | return sInstance;
65 | }
66 |
67 | private static synchronized ExecutorService getThreadPool() {
68 | if (null == threadPool) {
69 | threadPool = Executors.newCachedThreadPool();
70 | }
71 | return threadPool;
72 | }
73 |
74 | public void connectWideRouter() {
75 | Intent binderIntent = new Intent(mApplication, WideRouterConnectService.class);
76 | binderIntent.putExtra("domain", mProcessName);
77 | mApplication.bindService(binderIntent, mServiceConnection, BIND_AUTO_CREATE);
78 | }
79 |
80 | public void disconnectWideRouter() {
81 | if (null == mServiceConnection) {
82 | return;
83 | }
84 | mApplication.unbindService(mServiceConnection);
85 | mWideRouterAIDL = null;
86 | }
87 |
88 | public void registerProvider(String providerName, MaProvider provider) {
89 | mProviders.put(providerName, provider);
90 | }
91 |
92 |
93 | public boolean checkWideRouterConnection() {
94 | boolean result = false;
95 | if (mWideRouterAIDL != null) {
96 | result = true;
97 | }
98 | return result;
99 | }
100 |
101 | boolean answerWiderAsync(@NonNull RouterRequest routerRequest) {
102 | if (mProcessName.equals(routerRequest.getDomain()) && checkWideRouterConnection()) {
103 | return findRequestAction(routerRequest).isAsync(mApplication, routerRequest.getData());
104 | } else {
105 | return true;
106 | }
107 | }
108 |
109 | public RouterResponse route(Context context, @NonNull RouterRequest routerRequest) throws Exception {
110 | Logger.d(TAG, "Process:" + mProcessName + "\nLocal route start: " + System.currentTimeMillis());
111 | RouterResponse routerResponse = new RouterResponse();
112 | // Local request
113 | if (mProcessName.equals(routerRequest.getDomain())) {
114 | HashMap params = new HashMap<>();
115 | Object attachment = routerRequest.getAndClearObject();
116 | params.putAll(routerRequest.getData());
117 | Logger.d(TAG, "Process:" + mProcessName + "\nLocal find action start: " + System.currentTimeMillis());
118 | MaAction targetAction = findRequestAction(routerRequest);
119 | routerRequest.isIdle.set(true);
120 | Logger.d(TAG, "Process:" + mProcessName + "\nLocal find action end: " + System.currentTimeMillis());
121 | routerResponse.mIsAsync = attachment == null ? targetAction.isAsync(context, params) : targetAction.isAsync(context, params, attachment);
122 | // Sync result, return the result immediately.
123 | if (!routerResponse.mIsAsync) {
124 | MaActionResult result = attachment == null ? targetAction.invoke(context, params) : targetAction.invoke(context, params, attachment);
125 | routerResponse.mResultString = result.toString();
126 | routerResponse.mObject = result.getObject();
127 | Logger.d(TAG, "Process:" + mProcessName + "\nLocal sync end: " + System.currentTimeMillis());
128 | }
129 | // Async result, use the thread pool to execute the task.
130 | else {
131 | LocalTask task = new LocalTask(routerResponse, params,attachment, context, targetAction);
132 | routerResponse.mAsyncResponse = getThreadPool().submit(task);
133 | }
134 | } else if (!mApplication.needMultipleProcess()) {
135 | throw new Exception("Please make sure the returned value of needMultipleProcess in MaApplication is true, so that you can invoke other process action.");
136 | }
137 | // IPC request
138 | else {
139 | String domain = routerRequest.getDomain();
140 | String routerRequestString = routerRequest.toString();
141 | routerRequest.isIdle.set(true);
142 | if (checkWideRouterConnection()) {
143 | Logger.d(TAG, "Process:" + mProcessName + "\nWide async check start: " + System.currentTimeMillis());
144 | //If you don't need wide async check, use "routerResponse.mIsAsync = false;" replace the next line to improve performance.
145 | routerResponse.mIsAsync = mWideRouterAIDL.checkResponseAsync(domain, routerRequestString);
146 | Logger.d(TAG, "Process:" + mProcessName + "\nWide async check end: " + System.currentTimeMillis());
147 | }
148 | // Has not connected with the wide router.
149 | else {
150 | routerResponse.mIsAsync = true;
151 | ConnectWideTask task = new ConnectWideTask(routerResponse, domain, routerRequestString);
152 | routerResponse.mAsyncResponse = getThreadPool().submit(task);
153 | return routerResponse;
154 | }
155 | if (!routerResponse.mIsAsync) {
156 | routerResponse.mResultString = mWideRouterAIDL.route(domain, routerRequestString);
157 | Logger.d(TAG, "Process:" + mProcessName + "\nWide sync end: " + System.currentTimeMillis());
158 | }
159 | // Async result, use the thread pool to execute the task.
160 | else {
161 | WideTask task = new WideTask(domain, routerRequestString);
162 | routerResponse.mAsyncResponse = getThreadPool().submit(task);
163 | }
164 | }
165 | return routerResponse;
166 | }
167 |
168 | public boolean stopSelf(Class extends LocalRouterConnectService> clazz) {
169 | if (checkWideRouterConnection()) {
170 | try {
171 | return mWideRouterAIDL.stopRouter(mProcessName);
172 | } catch (RemoteException e) {
173 | e.printStackTrace();
174 | return false;
175 | }
176 | } else {
177 | mApplication.stopService(new Intent(mApplication, clazz));
178 | return true;
179 | }
180 | }
181 |
182 | public void stopWideRouter() {
183 | if (checkWideRouterConnection()) {
184 | try {
185 | mWideRouterAIDL.stopRouter(WideRouter.PROCESS_NAME);
186 | } catch (RemoteException e) {
187 | e.printStackTrace();
188 | }
189 | } else {
190 | Logger.e(TAG, "This local router hasn't connected the wide router.");
191 | }
192 | }
193 |
194 | private MaAction findRequestAction(RouterRequest routerRequest) {
195 | MaProvider targetProvider = mProviders.get(routerRequest.getProvider());
196 | ErrorAction defaultNotFoundAction = new ErrorAction(false, MaActionResult.CODE_NOT_FOUND, "Not found the action.");
197 | if (null == targetProvider) {
198 | return defaultNotFoundAction;
199 | } else {
200 | MaAction targetAction = targetProvider.findAction(routerRequest.getAction());
201 | if (null == targetAction) {
202 | return defaultNotFoundAction;
203 | } else {
204 | return targetAction;
205 | }
206 | }
207 | }
208 |
209 | private class LocalTask implements Callable {
210 | private RouterResponse mResponse;
211 | private HashMap mRequestData;
212 | private Context mContext;
213 | private MaAction mAction;
214 | private Object mObject;
215 | public LocalTask(RouterResponse routerResponse, HashMap requestData,Object object, Context context, MaAction maAction) {
216 | this.mContext = context;
217 | this.mResponse = routerResponse;
218 | this.mRequestData = requestData;
219 | this.mAction = maAction;
220 | this.mObject = object;
221 | }
222 |
223 | @Override
224 | public String call() throws Exception {
225 | MaActionResult result = mObject == null ? mAction.invoke(mContext, mRequestData) : mAction.invoke(mContext, mRequestData, mObject);
226 | mResponse.mObject = result.getObject();
227 | Logger.d(TAG, "Process:" + mProcessName + "\nLocal async end: " + System.currentTimeMillis());
228 | return result.toString();
229 | }
230 | }
231 |
232 | private class WideTask implements Callable {
233 |
234 | private String mDomain;
235 | private String mRequestString;
236 |
237 | public WideTask(String domain, String requestString) {
238 | this.mDomain = domain;
239 | this.mRequestString = requestString;
240 | }
241 |
242 | @Override
243 | public String call() throws Exception {
244 | Logger.d(TAG, "Process:" + mProcessName + "\nWide async start: " + System.currentTimeMillis());
245 | String result = mWideRouterAIDL.route(mDomain, mRequestString);
246 | Logger.d(TAG, "Process:" + mProcessName + "\nWide async end: " + System.currentTimeMillis());
247 | return result;
248 | }
249 | }
250 |
251 | private class ConnectWideTask implements Callable {
252 | private RouterResponse mResponse;
253 | private String mDomain;
254 | private String mRequestString;
255 |
256 | public ConnectWideTask(RouterResponse routerResponse, String domain, String requestString) {
257 | this.mResponse = routerResponse;
258 | this.mDomain = domain;
259 | this.mRequestString = requestString;
260 | }
261 |
262 | @Override
263 | public String call() throws Exception {
264 | Logger.d(TAG, "Process:" + mProcessName + "\nBind wide router start: " + System.currentTimeMillis());
265 | connectWideRouter();
266 | int time = 0;
267 | while (true) {
268 | if (null == mWideRouterAIDL) {
269 | try {
270 | Thread.sleep(50);
271 | } catch (InterruptedException e) {
272 | e.printStackTrace();
273 | }
274 | time++;
275 | } else {
276 | break;
277 | }
278 | if (time >= 600) {
279 | ErrorAction defaultNotFoundAction = new ErrorAction(true, MaActionResult.CODE_CANNOT_BIND_WIDE, "Bind wide router time out. Can not bind wide router.");
280 | MaActionResult result = defaultNotFoundAction.invoke(mApplication, new HashMap());
281 | mResponse.mResultString = result.toString();
282 | return result.toString();
283 | }
284 | }
285 | Logger.d(TAG, "Process:" + mProcessName + "\nBind wide router end: " + System.currentTimeMillis());
286 | String result = mWideRouterAIDL.route(mDomain, mRequestString);
287 | Logger.d(TAG, "Process:" + mProcessName + "\nWide async end: " + System.currentTimeMillis());
288 | return result;
289 | }
290 | }
291 | }
292 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/router/LocalRouterConnectService.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore.router;
2 |
3 | import android.app.Service;
4 | import android.content.Intent;
5 | import android.os.IBinder;
6 | import android.os.RemoteException;
7 | import android.support.annotation.Nullable;
8 | import android.util.Log;
9 |
10 | import com.spinytech.macore.ILocalRouterAIDL;
11 | import com.spinytech.macore.MaActionResult;
12 | import com.spinytech.macore.MaApplication;
13 |
14 | /**
15 | * Created by wanglei on 2016/11/29.
16 | */
17 |
18 | public class LocalRouterConnectService extends Service {
19 |
20 | @Override
21 | public int onStartCommand(Intent intent, int flags, int startId) {
22 | return super.onStartCommand(intent, flags, startId);
23 | }
24 |
25 | @Nullable
26 | @Override
27 | public IBinder onBind(Intent intent) {
28 | Log.e("MRCS","onBind");
29 | return stub;
30 | }
31 |
32 | ILocalRouterAIDL.Stub stub = new ILocalRouterAIDL.Stub() {
33 |
34 | @Override
35 | public boolean checkResponseAsync(String routerRequest) throws RemoteException {
36 | return LocalRouter.getInstance(MaApplication.getMaApplication()).
37 | answerWiderAsync(new RouterRequest
38 | .Builder(getApplicationContext())
39 | .json(routerRequest)
40 | .build());
41 | }
42 |
43 | @Override
44 | public String route(String routerRequest) {
45 | try {
46 | LocalRouter localRouter = LocalRouter.getInstance(MaApplication.getMaApplication());
47 | RouterRequest routerRequest1 = new RouterRequest
48 | .Builder(getApplicationContext())
49 | .json(routerRequest)
50 | .build();
51 | RouterResponse routerResponse = localRouter.route(LocalRouterConnectService.this,routerRequest1);
52 | return routerResponse.get();
53 | } catch (Exception e) {
54 | e.printStackTrace();
55 | return new MaActionResult.Builder().msg(e.getMessage()).build().toString();
56 | }
57 | }
58 |
59 | @Override
60 | public boolean stopWideRouter() throws RemoteException {
61 | LocalRouter
62 | .getInstance(MaApplication.getMaApplication())
63 | .disconnectWideRouter();
64 | return true;
65 | }
66 |
67 | @Override
68 | public void connectWideRouter() throws RemoteException {
69 | LocalRouter
70 | .getInstance(MaApplication.getMaApplication())
71 | .connectWideRouter();
72 | }
73 | };
74 | }
75 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/router/RouterRequest.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore.router;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 |
6 | import com.spinytech.macore.tools.Logger;
7 | import com.spinytech.macore.tools.ProcessUtil;
8 |
9 | import org.json.JSONException;
10 | import org.json.JSONObject;
11 |
12 | import java.io.UnsupportedEncodingException;
13 | import java.net.URLDecoder;
14 | import java.util.HashMap;
15 | import java.util.Iterator;
16 | import java.util.Map;
17 | import java.util.concurrent.atomic.AtomicBoolean;
18 | import java.util.concurrent.atomic.AtomicInteger;
19 |
20 | /**
21 | * Created by wanglei on 2016/12/27.
22 | */
23 |
24 | public class RouterRequest {
25 | private static final String TAG = "RouterRequest";
26 | private static volatile String DEFAULT_PROCESS = "";
27 | private String from;
28 | private String domain;
29 | private String provider;
30 | private String action;
31 | private HashMap data;
32 | private Object object;
33 | AtomicBoolean isIdle = new AtomicBoolean(true);
34 |
35 | private static final int length = 64;
36 | private static AtomicInteger sIndex = new AtomicInteger(0);
37 | private static final int RESET_NUM = 1000;
38 | private static volatile RouterRequest[] table = new RouterRequest[length];
39 |
40 | static {
41 | for (int i = 0; i < length; i++) {
42 | table[i] = new RouterRequest();
43 | }
44 | }
45 |
46 | private RouterRequest() {
47 | this.from = DEFAULT_PROCESS;
48 | this.domain = DEFAULT_PROCESS;
49 | this.provider = "";
50 | this.action = "";
51 | this.data = new HashMap<>();
52 | }
53 |
54 |
55 | private RouterRequest(Context context) {
56 | this.from = getProcess(context);
57 | this.domain = getProcess(context);
58 | this.provider = "";
59 | this.action = "";
60 | this.data = new HashMap<>();
61 | }
62 |
63 | private RouterRequest(Builder builder) {
64 | this.from = builder.mFrom;
65 | this.domain = builder.mDomain;
66 | this.provider = builder.mProvider;
67 | this.action = builder.mAction;
68 | this.data = builder.mData;
69 | }
70 |
71 | public String getFrom() {
72 | return from;
73 | }
74 |
75 | public String getDomain() {
76 | return domain;
77 | }
78 |
79 | public String getProvider() {
80 | return provider;
81 | }
82 |
83 | public String getAction() {
84 | return action;
85 | }
86 |
87 | public HashMap getData() {
88 | return data;
89 | }
90 |
91 | public Object getAndClearObject() {
92 | Object temp = object;
93 | object = null;
94 | return temp;
95 | }
96 |
97 | private static String getProcess(Context context) {
98 | if (TextUtils.isEmpty(DEFAULT_PROCESS) || ProcessUtil.UNKNOWN_PROCESS_NAME.equals(DEFAULT_PROCESS)) {
99 | DEFAULT_PROCESS = ProcessUtil.getProcessName(context, ProcessUtil.getMyProcessId());
100 | }
101 | return DEFAULT_PROCESS;
102 | }
103 |
104 | @Override
105 | public String toString() {
106 | //Here remove Gson to save about 10ms.
107 | //String result = new Gson().toJson(this);
108 | JSONObject jsonObject = new JSONObject();
109 | try {
110 | jsonObject.put("from", from);
111 | jsonObject.put("domain", domain);
112 | jsonObject.put("provider", provider);
113 | jsonObject.put("action", action);
114 |
115 | try {
116 | JSONObject jsonData = new JSONObject();
117 | for (Map.Entry entry : data.entrySet()) {
118 | jsonData.put(entry.getKey(), entry.getValue());
119 | }
120 | jsonObject.put("data", jsonData);
121 | } catch (Exception e) {
122 | e.printStackTrace();
123 | jsonObject.put("data", "{}");
124 | }
125 | } catch (JSONException e) {
126 | e.printStackTrace();
127 | }
128 |
129 | return jsonObject.toString();
130 | }
131 |
132 | public RouterRequest json(String requestJsonString) {
133 | //Here remove Gson to save about 10ms.
134 | //RouterRequest routerRequest = new Gson().fromJson(requestJsonString, RouterRequest.class);
135 | try {
136 | JSONObject jsonObject = new JSONObject(requestJsonString);
137 | this.from = jsonObject.getString("from");
138 | this.domain = jsonObject.getString("domain");
139 | this.provider = jsonObject.getString("provider");
140 | this.action = jsonObject.getString("action");
141 | try {
142 | JSONObject jsonData = new JSONObject(jsonObject.getString("data"));
143 | Iterator it = jsonData.keys();
144 | while (it.hasNext()) {
145 | String key = String.valueOf(it.next());
146 | String value = (String) jsonData.get(key);
147 | this.data.put(key, value);
148 | }
149 | } catch (Exception e) {
150 | e.printStackTrace();
151 | this.data = new HashMap<>();
152 | }
153 | } catch (JSONException e) {
154 | e.printStackTrace();
155 | }
156 | return this;
157 | }
158 |
159 | public RouterRequest url(String url) {
160 | int questIndex = url.indexOf('?');
161 | String[] urls = url.split("\\?");
162 | if (urls.length != 1 && urls.length != 2) {
163 | Logger.e(TAG, "The url is illegal.");
164 | return this;
165 | }
166 | String[] targets = urls[0].split("/");
167 | if (targets.length == 3) {
168 | this.domain = targets[0];
169 | this.provider = targets[1];
170 | this.action = targets[2];
171 | } else {
172 | Logger.e(TAG, "The url is illegal.");
173 | return this;
174 | }
175 | //Add params
176 | if (questIndex != -1) {
177 | String queryString = urls[1];
178 | if (queryString != null && queryString.length() > 0) {
179 | int ampersandIndex, lastAmpersandIndex = 0;
180 | String subStr, key, value;
181 | String[] paramPair, values, newValues;
182 | do {
183 | ampersandIndex = queryString.indexOf('&', lastAmpersandIndex) + 1;
184 | if (ampersandIndex > 0) {
185 | subStr = queryString.substring(lastAmpersandIndex, ampersandIndex - 1);
186 | lastAmpersandIndex = ampersandIndex;
187 | } else {
188 | subStr = queryString.substring(lastAmpersandIndex);
189 | }
190 | paramPair = subStr.split("=");
191 | key = paramPair[0];
192 | value = paramPair.length == 1 ? "" : paramPair[1];
193 | try {
194 | value = URLDecoder.decode(value, "UTF-8");
195 | } catch (UnsupportedEncodingException e) {
196 | e.printStackTrace();
197 | }
198 | data.put(key, value);
199 | } while (ampersandIndex > 0);
200 | }
201 | }
202 | return this;
203 | }
204 |
205 | public RouterRequest domain(String domain) {
206 | this.domain = domain;
207 | return this;
208 | }
209 |
210 |
211 | public RouterRequest provider(String provider) {
212 | this.provider = provider;
213 | return this;
214 | }
215 |
216 |
217 | public RouterRequest action(String action) {
218 | this.action = action;
219 | return this;
220 | }
221 |
222 |
223 | public RouterRequest data(String key, String data) {
224 | this.data.put(key, data);
225 | return this;
226 | }
227 |
228 | public RouterRequest object(Object object) {
229 | this.object = object;
230 | return this;
231 | }
232 |
233 | public static RouterRequest obtain(Context context) {
234 | return obtain(context, 0);
235 | }
236 |
237 | private static RouterRequest obtain(Context context, int retryTime) {
238 | int index = sIndex.getAndIncrement();
239 | if (index > RESET_NUM) {
240 | sIndex.compareAndSet(index, 0);
241 | if (index > RESET_NUM * 2) {
242 | sIndex.set(0);
243 | }
244 | }
245 |
246 | int num = index & (length - 1);
247 |
248 | RouterRequest target = table[num];
249 |
250 | if (target.isIdle.compareAndSet(true, false)) {
251 | target.from = getProcess(context);
252 | target.domain = getProcess(context);
253 | target.provider = "";
254 | target.action = "";
255 | target.data.clear();
256 | return target;
257 | } else {
258 | if (retryTime < 5) {
259 | return obtain(context, retryTime++);
260 | } else {
261 | return new RouterRequest(context);
262 | }
263 |
264 | }
265 | }
266 |
267 | @Deprecated
268 | public static class Builder {
269 | private String mFrom;
270 | private String mDomain;
271 | private String mProvider;
272 | private String mAction;
273 | private HashMap mData;
274 |
275 | public Builder(Context context) {
276 | mFrom = getProcess(context);
277 | mDomain = getProcess(context);
278 | mProvider = "";
279 | mAction = "";
280 | mData = new HashMap<>();
281 | }
282 |
283 | public Builder json(String requestJsonString) {
284 | //Here remove Gson to save about 10ms.
285 | //RouterRequest routerRequest = new Gson().fromJson(requestJsonString, RouterRequest.class);
286 | try {
287 | JSONObject jsonObject = new JSONObject(requestJsonString);
288 | this.mFrom = jsonObject.getString("from");
289 | this.mDomain = jsonObject.getString("domain");
290 | this.mProvider = jsonObject.getString("provider");
291 | this.mAction = jsonObject.getString("action");
292 | try {
293 | JSONObject jsonData = new JSONObject(jsonObject.getString("data"));
294 | Iterator it = jsonData.keys();
295 | while (it.hasNext()) {
296 | String key = String.valueOf(it.next());
297 | String value = (String) jsonData.get(key);
298 | this.mData.put(key, value);
299 | }
300 | } catch (Exception e) {
301 | e.printStackTrace();
302 | this.mData = new HashMap<>();
303 | }
304 | } catch (JSONException e) {
305 | e.printStackTrace();
306 | }
307 | return this;
308 | }
309 |
310 | public Builder url(String url) {
311 | int questIndex = url.indexOf('?');
312 | String[] urls = url.split("\\?");
313 | if (urls.length != 1 && urls.length != 2) {
314 | Logger.e(TAG, "The url is illegal.");
315 | return this;
316 | }
317 | String[] targets = urls[0].split("/");
318 | if (targets.length == 3) {
319 | this.mDomain = targets[0];
320 | this.mProvider = targets[1];
321 | this.mAction = targets[2];
322 | } else {
323 | Logger.e(TAG, "The url is illegal.");
324 | return this;
325 | }
326 | //Add params
327 | if (questIndex != -1) {
328 | String queryString = urls[1];
329 | if (queryString != null && queryString.length() > 0) {
330 | int ampersandIndex, lastAmpersandIndex = 0;
331 | String subStr, key, value;
332 | String[] paramPair, values, newValues;
333 | do {
334 | ampersandIndex = queryString.indexOf('&', lastAmpersandIndex) + 1;
335 | if (ampersandIndex > 0) {
336 | subStr = queryString.substring(lastAmpersandIndex, ampersandIndex - 1);
337 | lastAmpersandIndex = ampersandIndex;
338 | } else {
339 | subStr = queryString.substring(lastAmpersandIndex);
340 | }
341 | paramPair = subStr.split("=");
342 | key = paramPair[0];
343 | value = paramPair.length == 1 ? "" : paramPair[1];
344 | try {
345 | value = URLDecoder.decode(value, "UTF-8");
346 | } catch (UnsupportedEncodingException e) {
347 | e.printStackTrace();
348 | }
349 | mData.put(key, value);
350 | } while (ampersandIndex > 0);
351 | }
352 | }
353 | return this;
354 | }
355 |
356 | public Builder domain(String domain) {
357 | this.mDomain = domain;
358 | return this;
359 | }
360 |
361 |
362 | public Builder provider(String provider) {
363 | this.mProvider = provider;
364 | return this;
365 | }
366 |
367 |
368 | public Builder action(String action) {
369 | this.mAction = action;
370 | return this;
371 | }
372 |
373 |
374 | public Builder data(String key, String data) {
375 | this.mData.put(key, data);
376 | return this;
377 | }
378 |
379 | public RouterRequest build() {
380 | return new RouterRequest(this);
381 | }
382 | }
383 |
384 | }
385 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/router/RouterResponse.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore.router;
2 |
3 | import org.json.JSONException;
4 | import org.json.JSONObject;
5 |
6 | import java.util.concurrent.Future;
7 | import java.util.concurrent.TimeUnit;
8 |
9 | /**
10 | * Created by wanglei on 2016/12/27.
11 | */
12 |
13 | public class RouterResponse {
14 |
15 | private static final int TIME_OUT = 30 * 1000;
16 |
17 | private long mTimeOut = 0;
18 | private boolean mHasGet = false;
19 | boolean mIsAsync = true;
20 |
21 | int mCode = -1;
22 |
23 | String mMessage = "";
24 |
25 | String mData;
26 |
27 | Object mObject;
28 |
29 | /**
30 | * This field is MaActionResult.toString()
31 | */
32 | String mResultString;
33 |
34 | Future mAsyncResponse;
35 |
36 | public RouterResponse() {
37 | this(TIME_OUT);
38 | }
39 |
40 | public RouterResponse(long timeout) {
41 | if (timeout > TIME_OUT * 2 || timeout < 0) {
42 | timeout = TIME_OUT;
43 | }
44 | mTimeOut = timeout;
45 | }
46 |
47 | public boolean isAsync() {
48 | return mIsAsync;
49 | }
50 |
51 | public String get() throws Exception {
52 | if (mIsAsync) {
53 | mResultString = mAsyncResponse.get(mTimeOut, TimeUnit.MILLISECONDS);
54 | parseResult();
55 | }else{
56 | parseResult();
57 | }
58 | return mResultString;
59 | }
60 |
61 | private void parseResult(){
62 | if (!mHasGet) {
63 | try {
64 | JSONObject jsonObject = new JSONObject(mResultString);
65 | this.mCode = jsonObject.getInt("code");
66 | this.mMessage = jsonObject.getString("msg");
67 | this.mData = jsonObject.getString("data");
68 | } catch (JSONException e) {
69 | e.printStackTrace();
70 | }
71 | mHasGet = true;
72 | }
73 | }
74 |
75 | public int getCode() throws Exception {
76 | if (!mHasGet) {
77 | get();
78 | }
79 | return mCode;
80 | }
81 |
82 | public String getMessage() throws Exception {
83 | if (!mHasGet) {
84 | get();
85 | }
86 | return mMessage;
87 | }
88 |
89 | public String getData() throws Exception {
90 | if (!mHasGet) {
91 | get();
92 | }
93 | return mData;
94 | }
95 |
96 | public Object getObject() throws Exception {
97 | if (!mHasGet) {
98 | get();
99 | }
100 | return mObject;
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/router/WideRouter.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore.router;
2 |
3 | import android.content.ComponentName;
4 | import android.content.Intent;
5 | import android.content.ServiceConnection;
6 | import android.os.Bundle;
7 | import android.os.IBinder;
8 | import android.os.RemoteException;
9 | import android.support.annotation.NonNull;
10 | import android.text.TextUtils;
11 |
12 | import com.spinytech.macore.ILocalRouterAIDL;
13 | import com.spinytech.macore.MaActionResult;
14 | import com.spinytech.macore.MaApplication;
15 | import com.spinytech.macore.tools.Logger;
16 | import com.spinytech.macore.tools.ProcessUtil;
17 |
18 | import java.util.ArrayList;
19 | import java.util.HashMap;
20 | import java.util.List;
21 |
22 | import static android.content.Context.BIND_AUTO_CREATE;
23 |
24 | /**
25 | * Created by wanglei on 2016/11/29.
26 | */
27 |
28 | public class WideRouter {
29 | private static final String TAG = "WideRouter";
30 | public static final String PROCESS_NAME = "com.spiny.ma.widerouter";
31 | private static HashMap sLocalRouterClasses;
32 | private static WideRouter sInstance = null;
33 | private MaApplication mApplication;
34 | private HashMap mLocalRouterConnectionMap;
35 | private HashMap mLocalRouterAIDLMap;
36 | boolean mIsStopping = false;
37 |
38 | private WideRouter(MaApplication context) {
39 | mApplication = context;
40 | String checkProcessName = ProcessUtil.getProcessName(context, ProcessUtil.getMyProcessId());
41 | if (!PROCESS_NAME.equals(checkProcessName)) {
42 | throw new RuntimeException("You should not initialize the WideRouter in process:" + checkProcessName);
43 | }
44 | sLocalRouterClasses = new HashMap<>();
45 | mLocalRouterConnectionMap = new HashMap<>();
46 | mLocalRouterAIDLMap = new HashMap<>();
47 | }
48 |
49 | public static synchronized WideRouter getInstance(@NonNull MaApplication context) {
50 | if (sInstance == null) {
51 | sInstance = new WideRouter(context);
52 | }
53 | return sInstance;
54 | }
55 |
56 | public static void registerLocalRouter(String processName, Class extends LocalRouterConnectService> targetClass) {
57 | if (null == sLocalRouterClasses) {
58 | sLocalRouterClasses = new HashMap<>();
59 | }
60 | ConnectServiceWrapper connectServiceWrapper = new ConnectServiceWrapper(targetClass);
61 | sLocalRouterClasses.put(processName, connectServiceWrapper);
62 | }
63 |
64 | boolean checkLocalRouterHasRegistered(final String domain) {
65 | ConnectServiceWrapper connectServiceWrapper = sLocalRouterClasses.get(domain);
66 | if(null == connectServiceWrapper){
67 | return false;
68 | }
69 | Class extends LocalRouterConnectService> clazz = connectServiceWrapper.targetClass;
70 | if (null == clazz) {
71 | return false;
72 | } else {
73 | return true;
74 | }
75 | }
76 |
77 | boolean connectLocalRouter(final String domain) {
78 | ConnectServiceWrapper connectServiceWrapper = sLocalRouterClasses.get(domain);
79 | if(null == connectServiceWrapper){
80 | return false;
81 | }
82 | Class extends LocalRouterConnectService> clazz = connectServiceWrapper.targetClass;
83 | if (null == clazz) {
84 | return false;
85 | }
86 | Intent binderIntent = new Intent(mApplication, clazz);
87 | Bundle bundle = new Bundle();
88 | binderIntent.putExtras(bundle);
89 | final ServiceConnection serviceConnection = new ServiceConnection() {
90 | @Override
91 | public void onServiceConnected(ComponentName name, IBinder service) {
92 | ILocalRouterAIDL mLocalRouterAIDL = ILocalRouterAIDL.Stub.asInterface(service);
93 | ILocalRouterAIDL temp = mLocalRouterAIDLMap.get(domain);
94 | if (null == temp) {
95 | mLocalRouterAIDLMap.put(domain, mLocalRouterAIDL);
96 | mLocalRouterConnectionMap.put(domain, this);
97 | try {
98 | mLocalRouterAIDL.connectWideRouter();
99 | } catch (RemoteException e) {
100 | e.printStackTrace();
101 | }
102 | }
103 | }
104 |
105 | @Override
106 | public void onServiceDisconnected(ComponentName name) {
107 | mLocalRouterAIDLMap.remove(domain);
108 | mLocalRouterConnectionMap.remove(domain);
109 | }
110 | };
111 | mApplication.bindService(binderIntent, serviceConnection, BIND_AUTO_CREATE);
112 | return true;
113 | }
114 |
115 | boolean disconnectLocalRouter(String domain) {
116 | if (TextUtils.isEmpty(domain)) {
117 | return false;
118 | } else if (PROCESS_NAME.equals(domain)) {
119 | stopSelf();
120 | return true;
121 | } else if (null == mLocalRouterConnectionMap.get(domain)) {
122 | return false;
123 | } else {
124 | ILocalRouterAIDL aidl = mLocalRouterAIDLMap.get(domain);
125 | if (null != aidl) {
126 | try {
127 | aidl.stopWideRouter();
128 | } catch (RemoteException e) {
129 | e.printStackTrace();
130 | }
131 | }
132 | mApplication.unbindService(mLocalRouterConnectionMap.get(domain));
133 | mLocalRouterAIDLMap.remove(domain);
134 | mLocalRouterConnectionMap.remove(domain);
135 | return true;
136 | }
137 | }
138 |
139 | /**
140 | */
141 | void stopSelf() {
142 | mIsStopping = true;
143 | new Thread(new Runnable() {
144 | @Override
145 | public void run() {
146 | List locals = new ArrayList<>();
147 | locals.addAll(mLocalRouterAIDLMap.keySet());
148 | for (String domain : locals) {
149 | ILocalRouterAIDL aidl = mLocalRouterAIDLMap.get(domain);
150 | if (null != aidl) {
151 | try {
152 | aidl.stopWideRouter();
153 | } catch (RemoteException e) {
154 | e.printStackTrace();
155 | }
156 | mApplication.unbindService(mLocalRouterConnectionMap.get(domain));
157 | mLocalRouterAIDLMap.remove(domain);
158 | mLocalRouterConnectionMap.remove(domain);
159 | }
160 | }
161 | try {
162 | Thread.sleep(1000);
163 | mApplication.stopService(new Intent(mApplication, WideRouterConnectService.class));
164 | Thread.sleep(1000);
165 | } catch (InterruptedException e) {
166 | e.printStackTrace();
167 | }
168 | System.exit(0);
169 | }
170 | }).start();
171 | }
172 |
173 | boolean answerLocalAsync(String domain, String routerRequest) {
174 | ILocalRouterAIDL target = mLocalRouterAIDLMap.get(domain);
175 | if (target == null) {
176 | ConnectServiceWrapper connectServiceWrapper = sLocalRouterClasses.get(domain);
177 | if(null == connectServiceWrapper){
178 | return false;
179 | }
180 | Class extends LocalRouterConnectService> clazz = connectServiceWrapper.targetClass;
181 | if (null == clazz) {
182 | return false;
183 | } else {
184 | return true;
185 | }
186 | } else {
187 | try {
188 | return target.checkResponseAsync(routerRequest);
189 | } catch (RemoteException e) {
190 | e.printStackTrace();
191 | return true;
192 | }
193 | }
194 | }
195 |
196 | public RouterResponse route(String domain, String routerRequest) {
197 | Logger.d(TAG, "Process:" + PROCESS_NAME + "\nWide route start: " + System.currentTimeMillis());
198 | RouterResponse routerResponse = new RouterResponse();
199 | if (mIsStopping) {
200 |
201 | MaActionResult result = new MaActionResult.Builder()
202 | .code(MaActionResult.CODE_WIDE_STOPPING)
203 | .msg("Wide router is stopping.")
204 | .build();
205 | routerResponse.mIsAsync = true;
206 | routerResponse.mResultString = result.toString();
207 | return routerResponse;
208 | }
209 | if (PROCESS_NAME.equals(domain)) {
210 | MaActionResult result = new MaActionResult.Builder()
211 | .code(MaActionResult.CODE_TARGET_IS_WIDE)
212 | .msg("Domain can not be " + PROCESS_NAME + ".")
213 | .build();
214 | routerResponse.mIsAsync = true;
215 | routerResponse.mResultString = result.toString();
216 | return routerResponse;
217 | }
218 | ILocalRouterAIDL target = mLocalRouterAIDLMap.get(domain);
219 | if (null == target) {
220 | if (!connectLocalRouter(domain)) {
221 | MaActionResult result = new MaActionResult.Builder()
222 | .code(MaActionResult.CODE_ROUTER_NOT_REGISTER)
223 | .msg("The " + domain + " has not registered.")
224 | .build();
225 | routerResponse.mIsAsync = false;
226 | routerResponse.mResultString = result.toString();
227 | Logger.d(TAG, "Process:" + PROCESS_NAME + "\nLocal not register end: " + System.currentTimeMillis());
228 | return routerResponse;
229 | } else {
230 | // Wait to bind the target process connect service, timeout is 30s.
231 | Logger.d(TAG, "Process:" + PROCESS_NAME + "\nBind local router start: " + System.currentTimeMillis());
232 | int time = 0;
233 | while (true) {
234 | target = mLocalRouterAIDLMap.get(domain);
235 | if (null == target) {
236 | try {
237 | Thread.sleep(50);
238 | } catch (InterruptedException e) {
239 | e.printStackTrace();
240 | }
241 | time++;
242 | } else {
243 | Logger.d(TAG, "Process:" + PROCESS_NAME + "\nBind local router end: " + System.currentTimeMillis());
244 | break;
245 | }
246 | if (time >= 600) {
247 | MaActionResult result = new MaActionResult.Builder()
248 | .code(MaActionResult.CODE_CANNOT_BIND_LOCAL)
249 | .msg("Can not bind " + domain + ", time out.")
250 | .build();
251 | routerResponse.mResultString = result.toString();
252 | return routerResponse;
253 | }
254 | }
255 | }
256 | }
257 | try {
258 | Logger.d(TAG, "Process:" + PROCESS_NAME + "\nWide target start: " + System.currentTimeMillis());
259 | String resultString = target.route(routerRequest);
260 | routerResponse.mResultString = resultString;
261 | Logger.d(TAG, "Process:" + PROCESS_NAME + "\nWide route end: " + System.currentTimeMillis());
262 | } catch (RemoteException e) {
263 | e.printStackTrace();
264 | MaActionResult result = new MaActionResult.Builder()
265 | .code(MaActionResult.CODE_REMOTE_EXCEPTION)
266 | .msg(e.getMessage())
267 | .build();
268 | routerResponse.mResultString = result.toString();
269 | return routerResponse;
270 | }
271 | return routerResponse;
272 | }
273 |
274 | }
275 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/router/WideRouterApplicationLogic.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore.router;
2 |
3 | import com.spinytech.macore.multiprocess.BaseApplicationLogic;
4 |
5 | /**
6 | * Created by wanglei on 2016/11/25.
7 | */
8 |
9 | public final class WideRouterApplicationLogic extends BaseApplicationLogic {
10 | @Override
11 | public void onCreate() {
12 | super.onCreate();
13 | initRouter();
14 | }
15 |
16 | protected void initRouter() {
17 | WideRouter.getInstance(mApplication);
18 | mApplication.initializeAllProcessRouter();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/router/WideRouterConnectService.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore.router;
2 |
3 | import android.app.Service;
4 | import android.content.Intent;
5 | import android.os.IBinder;
6 | import android.os.RemoteException;
7 | import android.support.annotation.Nullable;
8 |
9 | import com.spinytech.macore.IWideRouterAIDL;
10 | import com.spinytech.macore.MaActionResult;
11 | import com.spinytech.macore.MaApplication;
12 | import com.spinytech.macore.tools.Logger;
13 |
14 |
15 | /**
16 | * Created by wanglei on 2016/11/29.
17 | */
18 |
19 | public final class WideRouterConnectService extends Service {
20 | private static final String TAG = "WideRouterConnectService";
21 |
22 | @Override
23 | public void onCreate() {
24 | super.onCreate();
25 | if (!(getApplication() instanceof MaApplication)) {
26 | throw new RuntimeException("Please check your AndroidManifest.xml and make sure the application is instance of MaApplication.");
27 | }
28 | }
29 |
30 | @Override
31 | public void onDestroy() {
32 | super.onDestroy();
33 | }
34 |
35 | @Override
36 | public int onStartCommand(Intent intent, int flags, int startId) {
37 | return START_NOT_STICKY;
38 | }
39 |
40 | @Nullable
41 | @Override
42 | public IBinder onBind(Intent intent) {
43 | String domain = intent.getStringExtra("domain");
44 | if (WideRouter.getInstance(MaApplication.getMaApplication()).mIsStopping) {
45 | Logger.e(TAG, "Bind error: The wide router is stopping.");
46 | return null;
47 | }
48 | if (domain != null && domain.length() > 0) {
49 | boolean hasRegistered = WideRouter.getInstance(MaApplication.getMaApplication()).checkLocalRouterHasRegistered(domain);
50 | if (!hasRegistered) {
51 | Logger.e(TAG, "Bind error: The local router of process " + domain + " is not bidirectional." +
52 | "\nPlease create a Service extend LocalRouterConnectService then register it in AndroidManifest.xml and the initializeAllProcessRouter method of MaApplication." +
53 | "\nFor example:" +
54 | "\n" +
55 | "\nWideRouter.registerLocalRouter(\"your process name\",XXXConnectService.class);");
56 | return null;
57 | }
58 | WideRouter.getInstance(MaApplication.getMaApplication()).connectLocalRouter(domain);
59 | } else {
60 | Logger.e(TAG, "Bind error: Intent do not have \"domain\" extra!");
61 | return null;
62 | }
63 | return stub;
64 | }
65 |
66 | IWideRouterAIDL.Stub stub = new IWideRouterAIDL.Stub() {
67 |
68 | @Override
69 | public boolean checkResponseAsync(String domain, String routerRequest) throws RemoteException {
70 | return
71 | WideRouter.getInstance(MaApplication.getMaApplication())
72 | .answerLocalAsync(domain, routerRequest);
73 | }
74 |
75 | @Override
76 | public String route(String domain, String routerRequest) {
77 | try {
78 | return WideRouter.getInstance(MaApplication.getMaApplication())
79 | .route(domain, routerRequest)
80 | .mResultString;
81 | } catch (Exception e) {
82 | e.printStackTrace();
83 | return new MaActionResult.Builder()
84 | .code(MaActionResult.CODE_ERROR)
85 | .msg(e.getMessage())
86 | .build()
87 | .toString();
88 | }
89 | }
90 |
91 | @Override
92 | public boolean stopRouter(String domain) throws RemoteException {
93 | return WideRouter.getInstance(MaApplication.getMaApplication())
94 | .disconnectLocalRouter(domain);
95 | }
96 |
97 | };
98 | }
99 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/tools/Logger.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore.tools;
2 |
3 | import android.util.Log;
4 |
5 | /**
6 | * Created by wanglei on 2017/1/10.
7 | */
8 | public class Logger {
9 | public final static int ERROR = 1;
10 | public final static int WARN = 2;
11 | public final static int INFO = 3;
12 | public final static int DEBUG = 4;
13 | public final static int VERBOSE = 5;
14 |
15 | public static int LOG_LEVEL = ERROR;
16 |
17 |
18 | public static void e(String tag, String msg) {
19 | if (LOG_LEVEL >= ERROR)
20 | Log.e(tag, msg);
21 | }
22 |
23 | public static void w(String tag, String msg) {
24 | if (LOG_LEVEL >= WARN)
25 | Log.w(tag, msg);
26 | }
27 |
28 | public static void i(String tag, String msg) {
29 | if (LOG_LEVEL >= INFO)
30 | Log.i(tag, msg);
31 | }
32 |
33 | public static void d(String tag, String msg) {
34 | if (LOG_LEVEL >= DEBUG)
35 | Log.d(tag, msg);
36 | }
37 |
38 | public static void v(String tag, String msg) {
39 | if (LOG_LEVEL >= VERBOSE)
40 | Log.v(tag, msg);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/tools/ProcessUtil.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore.tools;
2 |
3 | import android.app.ActivityManager;
4 | import android.content.Context;
5 | import android.text.TextUtils;
6 |
7 | import java.io.BufferedReader;
8 | import java.io.File;
9 | import java.io.FileReader;
10 | import java.util.List;
11 |
12 | /**
13 | * Created by wanglei on 2016/11/25.
14 | */
15 |
16 | public class ProcessUtil {
17 |
18 | public static final String UNKNOWN_PROCESS_NAME = "unknown_process_name";
19 |
20 | public static int getMyProcessId() {
21 | return android.os.Process.myPid();
22 | }
23 |
24 | public static String getProcessName(int pid) {
25 | String processName = UNKNOWN_PROCESS_NAME;
26 | try {
27 | File file = new File("/proc/" + pid + "/" + "cmdline");
28 | BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
29 | processName = mBufferedReader.readLine().trim();
30 | mBufferedReader.close();
31 | return processName;
32 | } catch (Exception e) {
33 | e.printStackTrace();
34 | } finally {
35 | if (!TextUtils.isEmpty(processName)) {
36 | return processName;
37 | }
38 | }
39 | return UNKNOWN_PROCESS_NAME;
40 | }
41 |
42 | public static String getProcessName(Context context, int pid) {
43 | String processName = getProcessName(pid);
44 | if(UNKNOWN_PROCESS_NAME.equals(processName)){
45 | ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
46 | List runningApps = am.getRunningAppProcesses();
47 | if (runningApps == null) {
48 | return UNKNOWN_PROCESS_NAME;
49 | }
50 | for (ActivityManager.RunningAppProcessInfo procInfo : runningApps) {
51 | if (procInfo.pid == pid) {
52 | return procInfo.processName;
53 | }
54 | }
55 | }else{
56 | return processName;
57 | }
58 | return UNKNOWN_PROCESS_NAME;
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/macore/src/main/java/com/spinytech/macore/tools/RouterMessageUtil.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore.tools;
2 |
3 | /**
4 | * Created by wanglei on 2016/12/27.
5 | */
6 |
7 | public class RouterMessageUtil {
8 | }
9 |
--------------------------------------------------------------------------------
/macore/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MaCore
3 |
4 |
--------------------------------------------------------------------------------
/macore/src/test/java/com/spinytech/macore/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.macore;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/maindemo/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/maindemo/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 24
5 | buildToolsVersion "25.0.0"
6 |
7 | defaultConfig {
8 | applicationId "com.spinytech.maindemo"
9 | minSdkVersion 14
10 | targetSdkVersion 24
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 |
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | }
24 |
25 | dependencies {
26 | compile fileTree(dir: 'libs', include: ['*.jar'])
27 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
28 | exclude group: 'com.android.support', module: 'support-annotations'
29 | })
30 | compile 'com.android.support:appcompat-v7:24.2.1'
31 | testCompile 'junit:junit:4.12'
32 | compile project(':macore')
33 | compile project(':musicdemo')
34 | compile project(':picdemo')
35 | compile project(':webdemo')
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/maindemo/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/wanglei/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/maindemo/src/androidTest/java/com/spinytech/maindemo/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.maindemo;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.spinytech.maindemo", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/maindemo/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/maindemo/src/main/java/com/spinytech/maindemo/AsyncAction.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.maindemo;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 | import android.util.Log;
6 |
7 | import com.spinytech.macore.MaAction;
8 | import com.spinytech.macore.MaActionResult;
9 |
10 | import java.util.HashMap;
11 |
12 | /**
13 | * Created by wanglei on 2016/12/28.
14 | */
15 |
16 | public class AsyncAction extends MaAction {
17 |
18 | @Override
19 | public boolean isAsync(Context context, HashMap requestData) {
20 | return true;
21 | }
22 |
23 | @Override
24 | public MaActionResult invoke(Context context, HashMap requestData) {
25 | try {
26 | Thread.sleep(3000);
27 | } catch (InterruptedException e) {
28 | e.printStackTrace();
29 | }
30 | String temp = "";
31 | if(!TextUtils.isEmpty(requestData.get("1"))){
32 | temp+=requestData.get("1");
33 | }
34 | if(!TextUtils.isEmpty(requestData.get("2"))){
35 | temp+=requestData.get("2");
36 | }
37 | Log.e("AsyncAction",temp);
38 | MaActionResult result = new MaActionResult.Builder()
39 | .code(MaActionResult.CODE_SUCCESS)
40 | .msg("success")
41 | .data(temp)
42 | .object(null)
43 | .build();
44 | return result;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/maindemo/src/main/java/com/spinytech/maindemo/AttachObjectAction.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.maindemo;
2 |
3 | import android.content.Context;
4 | import android.widget.TextView;
5 | import android.widget.Toast;
6 |
7 | import com.spinytech.macore.MaAction;
8 | import com.spinytech.macore.MaActionResult;
9 |
10 | import java.util.HashMap;
11 |
12 | /**
13 | * Created by wanglei on 2017/2/15.
14 | */
15 |
16 | public class AttachObjectAction extends MaAction {
17 |
18 | // The two following methods are invalid when the request has object attachment.
19 | @Override
20 | public boolean isAsync(Context context, HashMap requestData) {
21 | return false;
22 | }
23 |
24 | @Override
25 | public MaActionResult invoke(Context context, HashMap requestData) {
26 | return new MaActionResult.Builder().code(MaActionResult.CODE_NOT_IMPLEMENT).msg("This method has not yet been implemented.").build();
27 | }
28 |
29 | // We should override the following two methods when the request has a object attachment.
30 | @Override
31 | public boolean isAsync(Context context, HashMap requestData, Object object) {
32 | return false;
33 | }
34 |
35 | @Override
36 | public MaActionResult invoke(Context context, HashMap requestData, Object object) {
37 | if (object instanceof TextView) {
38 | ((TextView) object).setText("The text is changed by AttachObjectAction.");
39 | Toast returnToast = Toast.makeText(context, "I am returned Toast.", Toast.LENGTH_SHORT);
40 | return new MaActionResult.Builder().code(MaActionResult.CODE_SUCCESS).msg("success").object(returnToast).build();
41 |
42 | }
43 | return super.invoke(context, requestData, object);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/maindemo/src/main/java/com/spinytech/maindemo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.maindemo;
2 |
3 | import android.os.Bundle;
4 | import android.os.Handler;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.view.View;
7 | import android.widget.Toast;
8 |
9 | import com.spinytech.macore.MaApplication;
10 | import com.spinytech.macore.router.LocalRouter;
11 | import com.spinytech.macore.router.RouterRequest;
12 | import com.spinytech.macore.router.RouterResponse;
13 |
14 | public class MainActivity extends AppCompatActivity {
15 |
16 | private Handler handler = new Handler();
17 |
18 | @Override
19 | protected void onCreate(Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | setContentView(R.layout.activity_main);
22 | findViewById(R.id.main_local_sync_btn).setOnClickListener(new View.OnClickListener() {
23 | @Override
24 | public void onClick(View v) {
25 | try {
26 | RouterResponse response = LocalRouter.getInstance(MaApplication.getMaApplication())
27 | .route(MainActivity.this, RouterRequest.obtain(MainActivity.this).provider("main")
28 | .action("sync")
29 | .data("1", "Hello")
30 | .data("2", "World"));
31 | Toast.makeText(MainActivity.this, response.get(), Toast.LENGTH_SHORT).show();
32 | } catch (Exception e) {
33 | e.printStackTrace();
34 | }
35 | }
36 | });
37 | findViewById(R.id.main_local_async_btn).setOnClickListener(new View.OnClickListener() {
38 | @Override
39 | public void onClick(View v) {
40 | try {
41 | final RouterResponse response = LocalRouter.getInstance(MaApplication.getMaApplication())
42 | .route(MainActivity.this, RouterRequest.obtain(MainActivity.this).provider("main")
43 | .action("async")
44 | .data("1", "Hello")
45 | .data("2", "World"));
46 | Toast.makeText(MainActivity.this, "please wait", Toast.LENGTH_SHORT).show();
47 | new Thread(new Runnable() {
48 | @Override
49 | public void run() {
50 | try {
51 | final String result = response.get();
52 | handler.post(new Runnable() {
53 | @Override
54 | public void run() {
55 | try {
56 | Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
57 | } catch (Exception e) {
58 | e.printStackTrace();
59 | }
60 | }
61 | });
62 | } catch (Exception e) {
63 | e.printStackTrace();
64 | }
65 |
66 | }
67 | }).start();
68 | } catch (Exception e) {
69 | e.printStackTrace();
70 | }
71 | }
72 | });
73 |
74 |
75 | findViewById(R.id.main_play_btn).setOnClickListener(new View.OnClickListener() {
76 | @Override
77 | public void onClick(View v) {
78 | final long startTime = System.currentTimeMillis();
79 | final RouterRequest request = new RouterRequest.Builder(getApplicationContext())
80 | .domain("com.spinytech.maindemo:music")
81 | .provider("music")
82 | .action("play")
83 | .build();
84 | try {
85 | final RouterResponse response = LocalRouter.getInstance(MaApplication.getMaApplication())
86 | .route(MainActivity.this, RouterRequest.obtain(MainActivity.this)
87 | .domain("com.spinytech.maindemo:music")
88 | .provider("music")
89 | .action("play"));
90 | response.isAsync();
91 | new Thread(new Runnable() {
92 | @Override
93 | public void run() {
94 | try {
95 | final String temp = response.getData();
96 | final long time = System.currentTimeMillis() - startTime;
97 | handler.post(new Runnable() {
98 | @Override
99 | public void run() {
100 | try {
101 | Toast.makeText(MainActivity.this, "async:" + response.isAsync() + " cost:" + time + " response:" + response.get(), Toast.LENGTH_SHORT).show();
102 | } catch (Exception e) {
103 | e.printStackTrace();
104 | }
105 | }
106 | });
107 | } catch (Exception e) {
108 | e.printStackTrace();
109 | }
110 | }
111 | }).start();
112 | } catch (Exception e) {
113 | e.printStackTrace();
114 | }
115 | }
116 | });
117 | findViewById(R.id.main_stop_btn).setOnClickListener(new View.OnClickListener() {
118 | @Override
119 | public void onClick(View v) {
120 | final long startTime = System.currentTimeMillis();
121 | try {
122 | final RouterResponse response = LocalRouter.getInstance(MaApplication.getMaApplication())
123 | .route(MainActivity.this, RouterRequest.obtain(MainActivity.this)
124 | .domain("com.spinytech.maindemo:music")
125 | .provider("music")
126 | .action("stop"));
127 | response.isAsync();
128 | new Thread(new Runnable() {
129 | @Override
130 | public void run() {
131 | try {
132 | final String temp = response.getData();
133 | final long time = System.currentTimeMillis() - startTime;
134 | handler.post(new Runnable() {
135 | @Override
136 | public void run() {
137 | try {
138 | Toast.makeText(MainActivity.this, "async:" + response.isAsync() + " cost:" + time + " response:" + response.get(), Toast.LENGTH_SHORT).show();
139 | } catch (Exception e) {
140 | e.printStackTrace();
141 | }
142 | }
143 | });
144 | } catch (Exception e) {
145 | e.printStackTrace();
146 | }
147 | }
148 | }).start();
149 | } catch (Exception e) {
150 | e.printStackTrace();
151 | }
152 | }
153 | });
154 |
155 |
156 | findViewById(R.id.main_music_shutdown_btn).setOnClickListener(new View.OnClickListener() {
157 | @Override
158 | public void onClick(View v) {
159 | final long startTime = System.currentTimeMillis();
160 | try {
161 | final RouterResponse response = LocalRouter.getInstance(MaApplication.getMaApplication())
162 | .route(MainActivity.this, RouterRequest.obtain(MainActivity.this)
163 | .domain("com.spinytech.maindemo:music")
164 | .provider("music")
165 | .action("shutdown"));
166 | response.isAsync();
167 | new Thread(new Runnable() {
168 | @Override
169 | public void run() {
170 | try {
171 | final String temp = response.getData();
172 | final long time = System.currentTimeMillis() - startTime;
173 | handler.post(new Runnable() {
174 | @Override
175 | public void run() {
176 | try {
177 | Toast.makeText(MainActivity.this, "async:" + response.isAsync() + " cost:" + time + " response:" + response.get(), Toast.LENGTH_SHORT).show();
178 | } catch (Exception e) {
179 | e.printStackTrace();
180 | }
181 | }
182 | });
183 | } catch (Exception e) {
184 | e.printStackTrace();
185 | }
186 | }
187 | }).start();
188 | } catch (Exception e) {
189 | e.printStackTrace();
190 | }
191 | }
192 | });
193 | findViewById(R.id.main_wide_shutdown_btn).setOnClickListener(new View.OnClickListener() {
194 | @Override
195 | public void onClick(View v) {
196 | LocalRouter.getInstance(MaApplication.getMaApplication()).stopWideRouter();
197 | }
198 | });
199 | findViewById(R.id.main_pic_btn).setOnClickListener(new View.OnClickListener() {
200 | @Override
201 | public void onClick(View v) {
202 | final long startTime = System.currentTimeMillis();
203 | try {
204 | final RouterResponse response = LocalRouter.getInstance(MaApplication.getMaApplication())
205 | .route(MainActivity.this, RouterRequest.obtain(MainActivity.this)
206 | .domain("com.spinytech.maindemo:pic")
207 | .provider("pic")
208 | .action("pic")
209 | .data("is_big", "0"));
210 | response.isAsync();
211 | new Thread(new Runnable() {
212 | @Override
213 | public void run() {
214 | try {
215 | final String temp = response.getData();
216 | final long time = System.currentTimeMillis() - startTime;
217 | handler.post(new Runnable() {
218 | @Override
219 | public void run() {
220 | try {
221 | Toast.makeText(MainActivity.this, "async:" + response.isAsync() + " cost:" + time + " response:" + response.get(), Toast.LENGTH_SHORT).show();
222 | } catch (Exception e) {
223 | e.printStackTrace();
224 | }
225 | }
226 | });
227 | } catch (Exception e) {
228 | e.printStackTrace();
229 | }
230 | }
231 | }).start();
232 | } catch (Exception e) {
233 | e.printStackTrace();
234 | }
235 | }
236 | });
237 |
238 | findViewById(R.id.main_big_pic_btn).setOnClickListener(new View.OnClickListener() {
239 | @Override
240 | public void onClick(View v) {
241 | final long startTime = System.currentTimeMillis();
242 | try {
243 | final RouterResponse response = LocalRouter.getInstance(MaApplication.getMaApplication())
244 | .route(MainActivity.this, RouterRequest.obtain(MainActivity.this)
245 | .domain("com.spinytech.maindemo:pic")
246 | .provider("pic")
247 | .action("pic")
248 | .data("is_big", "1"));
249 | response.isAsync();
250 | new Thread(new Runnable() {
251 | @Override
252 | public void run() {
253 | try {
254 | final String temp = response.getData();
255 | final long time = System.currentTimeMillis() - startTime;
256 | handler.post(new Runnable() {
257 | @Override
258 | public void run() {
259 | try {
260 | Toast.makeText(MainActivity.this, "async:" + response.isAsync() + " cost:" + time + " response:" + response.get(), Toast.LENGTH_SHORT).show();
261 | } catch (Exception e) {
262 | e.printStackTrace();
263 | }
264 | }
265 | });
266 | } catch (Exception e) {
267 | e.printStackTrace();
268 | }
269 | }
270 | }).start();
271 | } catch (Exception e) {
272 | e.printStackTrace();
273 | }
274 | }
275 | });
276 | findViewById(R.id.main_web_btn).setOnClickListener(new View.OnClickListener() {
277 | @Override
278 | public void onClick(View v) {
279 | try {
280 | LocalRouter.getInstance(MaApplication.getMaApplication())
281 | .route(MainActivity.this, RouterRequest.obtain(MainActivity.this)
282 | .provider("web")
283 | .action("web")
284 | );
285 | } catch (Exception e) {
286 | e.printStackTrace();
287 | }
288 | }
289 | });
290 | findViewById(R.id.main_attach_btn).setOnClickListener(new View.OnClickListener() {
291 | @Override
292 | public void onClick(View v) {
293 | try {
294 | RouterResponse response = LocalRouter.getInstance(MaApplication.getMaApplication())
295 | .route(MainActivity.this, RouterRequest.obtain(MainActivity.this)
296 | .provider("main")
297 | .action("attachment")
298 | .object(findViewById(R.id.main_attach_btn))
299 | );
300 | if(response.getObject() instanceof Toast){
301 | ((Toast)response.getObject()).show();
302 | }
303 | } catch (Exception e) {
304 | e.printStackTrace();
305 | }
306 | }
307 | });
308 | }
309 |
310 | }
311 |
--------------------------------------------------------------------------------
/maindemo/src/main/java/com/spinytech/maindemo/MainApplicationLogic.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.maindemo;
2 |
3 | import com.spinytech.macore.multiprocess.BaseApplicationLogic;
4 | import com.spinytech.macore.router.LocalRouter;
5 |
6 | /**
7 | * Created by wanglei on 2016/11/29.
8 | */
9 |
10 | public class MainApplicationLogic extends BaseApplicationLogic {
11 | @Override
12 | public void onCreate() {
13 | super.onCreate();
14 | LocalRouter.getInstance(mApplication).registerProvider("main",new MainProvider());
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/maindemo/src/main/java/com/spinytech/maindemo/MainProvider.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.maindemo;
2 |
3 | import com.spinytech.macore.MaProvider;
4 |
5 | /**
6 | * Created by wanglei on 2016/12/28.
7 | */
8 |
9 | public class MainProvider extends MaProvider {
10 | @Override
11 | protected void registerActions() {
12 | registerAction("sync",new SyncAction());
13 | registerAction("async",new AsyncAction());
14 | registerAction("attachment",new AttachObjectAction());
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/maindemo/src/main/java/com/spinytech/maindemo/MainRouterConnectService.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.maindemo;
2 |
3 | import com.spinytech.macore.router.LocalRouterConnectService;
4 |
5 | /**
6 | * Created by wanglei on 2016/12/28.
7 | */
8 |
9 | public class MainRouterConnectService extends LocalRouterConnectService {
10 | }
11 |
--------------------------------------------------------------------------------
/maindemo/src/main/java/com/spinytech/maindemo/MyApplication.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.maindemo;
2 |
3 | import com.spinytech.macore.MaApplication;
4 | import com.spinytech.macore.router.WideRouter;
5 | import com.spinytech.musicdemo.MusicApplicationLogic;
6 | import com.spinytech.musicdemo.MusicRouterConnectService;
7 | import com.spinytech.picdemo.PicApplicationLogic;
8 | import com.spinytech.picdemo.PicRouterConnectService;
9 | import com.spinytech.webdemo.WebApplicationLogic;
10 |
11 | /**
12 | * Created by wanglei on 2016/11/29.
13 | */
14 |
15 | public class MyApplication extends MaApplication {
16 | @Override
17 | public void initializeAllProcessRouter() {
18 | WideRouter.registerLocalRouter("com.spinytech.maindemo",MainRouterConnectService.class);
19 | WideRouter.registerLocalRouter("com.spinytech.maindemo:music",MusicRouterConnectService.class);
20 | WideRouter.registerLocalRouter("com.spinytech.maindemo:pic",PicRouterConnectService.class);
21 | }
22 |
23 | @Override
24 | protected void initializeLogic() {
25 | registerApplicationLogic("com.spinytech.maindemo",999, MainApplicationLogic.class);
26 | registerApplicationLogic("com.spinytech.maindemo",998, WebApplicationLogic.class);
27 | registerApplicationLogic("com.spinytech.maindemo:music",999, MusicApplicationLogic.class);
28 | registerApplicationLogic("com.spinytech.maindemo:pic",999, PicApplicationLogic.class);
29 | }
30 |
31 | @Override
32 | public boolean needMultipleProcess() {
33 | return true;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/maindemo/src/main/java/com/spinytech/maindemo/SyncAction.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.maindemo;
2 |
3 | import android.content.Context;
4 | import android.text.TextUtils;
5 | import android.widget.Toast;
6 |
7 | import com.spinytech.macore.MaAction;
8 | import com.spinytech.macore.MaActionResult;
9 |
10 | import java.util.HashMap;
11 |
12 | /**
13 | * Created by wanglei on 2016/12/28.
14 | */
15 |
16 | public class SyncAction extends MaAction {
17 |
18 | @Override
19 | public boolean isAsync(Context context, HashMap requestData) {
20 | return false;
21 | }
22 |
23 | @Override
24 | public MaActionResult invoke(Context context, HashMap requestData) {
25 | String temp = "";
26 | if(!TextUtils.isEmpty(requestData.get("1"))){
27 | temp+=requestData.get("1");
28 | }
29 | if(!TextUtils.isEmpty(requestData.get("2"))){
30 | temp+=requestData.get("2");
31 | }
32 | Toast.makeText(context, "SyncAction.invoke:"+temp, Toast.LENGTH_SHORT).show();
33 | MaActionResult result = new MaActionResult.Builder()
34 | .code(MaActionResult.CODE_SUCCESS)
35 | .msg("success")
36 | .data(temp)
37 | .object(null)
38 | .build();
39 | return result;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/maindemo/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
14 |
15 |
21 |
22 |
28 |
29 |
35 |
36 |
42 |
43 |
44 |
50 |
51 |
57 |
58 |
64 |
65 |
71 |
72 |
78 |
79 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/maindemo/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpinyTech/ModularizationArchitecture/7b91fb7cd2c53b46379228cac76fbbda051a26db/maindemo/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/maindemo/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpinyTech/ModularizationArchitecture/7b91fb7cd2c53b46379228cac76fbbda051a26db/maindemo/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/maindemo/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpinyTech/ModularizationArchitecture/7b91fb7cd2c53b46379228cac76fbbda051a26db/maindemo/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/maindemo/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpinyTech/ModularizationArchitecture/7b91fb7cd2c53b46379228cac76fbbda051a26db/maindemo/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/maindemo/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpinyTech/ModularizationArchitecture/7b91fb7cd2c53b46379228cac76fbbda051a26db/maindemo/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/maindemo/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/maindemo/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/maindemo/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/maindemo/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MainDemo
3 |
4 |
--------------------------------------------------------------------------------
/maindemo/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/maindemo/src/test/java/com/spinytech/maindemo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.maindemo;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/musicdemo/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/musicdemo/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 24
5 | buildToolsVersion "25.0.0"
6 |
7 | defaultConfig {
8 | minSdkVersion 14
9 | targetSdkVersion 24
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | compile fileTree(dir: 'libs', include: ['*.jar'])
26 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
27 | exclude group: 'com.android.support', module: 'support-annotations'
28 | })
29 | compile 'com.android.support:appcompat-v7:24.2.1'
30 | testCompile 'junit:junit:4.12'
31 | compile project(':macore')
32 | }
33 |
--------------------------------------------------------------------------------
/musicdemo/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/wanglei/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/musicdemo/src/androidTest/java/com/spinytech/musicdemo/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.musicdemo;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.spinytech.musicdemo.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/musicdemo/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
6 |
7 |
9 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/musicdemo/src/main/java/com/spinytech/musicdemo/Music.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.musicdemo;
2 |
3 | import android.content.Context;
4 | import android.media.MediaPlayer;
5 |
6 | /**
7 | * Created by wanglei on 2016/12/27.
8 | */
9 | public class Music {
10 | MediaPlayer mp;
11 |
12 | public Music(Context context) {
13 | mp = MediaPlayer.create(context, R.raw.music);
14 | }
15 |
16 | public void play() {
17 | try {
18 | if (mp != null) {
19 | mp.stop();
20 | }
21 | mp.prepare();
22 | mp.start();
23 | } catch (Exception e) {
24 | e.printStackTrace();
25 | }
26 | }
27 |
28 | public void stop() {
29 | try {
30 | if (mp != null) {
31 | mp.stop();
32 | }
33 | } catch (Exception e) {
34 | e.printStackTrace();
35 | }
36 |
37 | }
38 | }
--------------------------------------------------------------------------------
/musicdemo/src/main/java/com/spinytech/musicdemo/MusicApplicationLogic.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.musicdemo;
2 |
3 | import com.spinytech.macore.multiprocess.BaseApplicationLogic;
4 | import com.spinytech.macore.router.LocalRouter;
5 |
6 | /**
7 | * Created by wanglei on 2016/11/30.
8 | */
9 |
10 | public class MusicApplicationLogic extends BaseApplicationLogic {
11 | @Override
12 | public void onCreate() {
13 | super.onCreate();
14 | LocalRouter.getInstance(mApplication).registerProvider("music",new MusicProvider());
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/musicdemo/src/main/java/com/spinytech/musicdemo/MusicProvider.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.musicdemo;
2 |
3 | import com.spinytech.macore.MaProvider;
4 |
5 | /**
6 | * Created by wanglei on 2016/12/28.
7 | */
8 |
9 | public class MusicProvider extends MaProvider{
10 | @Override
11 | protected void registerActions() {
12 | registerAction("play",new PlayAction());
13 | registerAction("stop",new StopAction());
14 | registerAction("shutdown",new ShutdownAction());
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/musicdemo/src/main/java/com/spinytech/musicdemo/MusicRouterConnectService.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.musicdemo;
2 |
3 | import android.content.Intent;
4 | import android.util.Log;
5 |
6 | import com.spinytech.macore.router.LocalRouterConnectService;
7 |
8 | /**
9 | * Created by wanglei on 2016/12/28.
10 | */
11 |
12 | public class MusicRouterConnectService extends LocalRouterConnectService {
13 | @Override
14 | public boolean onUnbind(Intent intent) {
15 | Log.e("MRCS","onUnbind");
16 | return super.onUnbind(intent);
17 | }
18 |
19 | @Override
20 | public void onDestroy() {
21 | super.onDestroy();
22 | Log.e("MRCS","onDestroy");
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/musicdemo/src/main/java/com/spinytech/musicdemo/MusicService.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.musicdemo;
2 |
3 | /**
4 | * Created by wanglei on 2016/12/27.
5 | */
6 | import android.app.Service;
7 | import android.content.Intent;
8 | import android.os.IBinder;
9 | import android.util.Log;
10 |
11 | public class MusicService extends Service {
12 | public Music music;
13 |
14 | public MusicService() {
15 | }
16 |
17 | @Override
18 | public void onCreate() {
19 | super.onCreate();
20 | music = new Music(this);
21 | }
22 |
23 | @Override
24 | public int onStartCommand(Intent intent, int flags, int startId) {
25 | if(intent !=null){
26 | String command = intent.getStringExtra("command");
27 | if("play".equals(command)){
28 | music.play();
29 | }else if("stop".equals(command)){
30 | music.stop();
31 | }
32 | }
33 | return super.onStartCommand(intent, flags, startId);
34 | }
35 |
36 | @Override
37 | public IBinder onBind(Intent intent) {
38 | throw new UnsupportedOperationException("Not yet implemented");
39 | }
40 |
41 | @Override
42 | public void onDestroy() {
43 | super.onDestroy();
44 | Log.e("MusicService","onDestroy");
45 | }
46 | }
--------------------------------------------------------------------------------
/musicdemo/src/main/java/com/spinytech/musicdemo/PlayAction.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.musicdemo;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 |
6 | import com.spinytech.macore.MaAction;
7 | import com.spinytech.macore.MaActionResult;
8 |
9 | import java.util.HashMap;
10 |
11 | /**
12 | * Created by wanglei on 2016/12/28.
13 | */
14 |
15 | public class PlayAction extends MaAction {
16 |
17 | @Override
18 | public boolean isAsync(Context context, HashMap requestData) {
19 | return false;
20 | }
21 |
22 | @Override
23 | public MaActionResult invoke(Context context, HashMap requestData) {
24 | Intent intent = new Intent(context,MusicService.class);
25 | intent.putExtra("command","play");
26 | context.startService(intent);
27 | MaActionResult result = new MaActionResult.Builder()
28 | .code(MaActionResult.CODE_SUCCESS)
29 | .msg("play success")
30 | .data("")
31 | .object(null)
32 | .build();
33 | return result;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/musicdemo/src/main/java/com/spinytech/musicdemo/ShutdownAction.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.musicdemo;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.util.Log;
6 |
7 | import com.spinytech.macore.MaAction;
8 | import com.spinytech.macore.MaActionResult;
9 | import com.spinytech.macore.MaApplication;
10 | import com.spinytech.macore.router.LocalRouter;
11 |
12 | import java.util.HashMap;
13 |
14 | /**
15 | * Created by wanglei on 2016/12/28.
16 | */
17 |
18 | public class ShutdownAction extends MaAction {
19 |
20 | @Override
21 | public boolean isAsync(Context context, HashMap requestData) {
22 | return true;
23 | }
24 |
25 | @Override
26 | public MaActionResult invoke(Context context, HashMap requestData) {
27 | MaActionResult result = new MaActionResult.Builder()
28 | .code(MaActionResult.CODE_SUCCESS)
29 | .msg("success")
30 | .data("")
31 | .object(null)
32 | .build();
33 | context.getApplicationContext().stopService(new Intent(context,MusicService.class));
34 |
35 | boolean stopslef =LocalRouter.getInstance(MaApplication.getMaApplication()).stopSelf(MusicRouterConnectService.class);
36 | Log.e("stopslef",""+stopslef);
37 | new Thread(new Runnable() {
38 | @Override
39 | public void run() {
40 | try {
41 | Thread.sleep(1000);
42 | } catch (InterruptedException e) {
43 | e.printStackTrace();
44 | }
45 | System.exit(0);
46 | }
47 | }).start();
48 | return result;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/musicdemo/src/main/java/com/spinytech/musicdemo/StopAction.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.musicdemo;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 |
6 | import com.spinytech.macore.MaAction;
7 | import com.spinytech.macore.MaActionResult;
8 | import com.spinytech.macore.tools.Logger;
9 |
10 | import java.util.HashMap;
11 |
12 | /**
13 | * Created by wanglei on 2016/12/28.
14 | */
15 |
16 | public class StopAction extends MaAction {
17 |
18 | @Override
19 | public boolean isAsync(Context context, HashMap requestData) {
20 | return false;
21 | }
22 |
23 | @Override
24 | public MaActionResult invoke(Context context, HashMap requestData) {
25 | Intent intent = new Intent(context, MusicService.class);
26 | intent.putExtra("command", "stop");
27 | context.startService(intent);
28 | MaActionResult result = new MaActionResult.Builder()
29 | .code(MaActionResult.CODE_SUCCESS)
30 | .msg("stop success")
31 | .data("")
32 | .object(null)
33 | .build();
34 |
35 | Logger.d("StopAction", "\nStopAction end: " + System.currentTimeMillis());
36 | return result;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/musicdemo/src/main/res/raw/music.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpinyTech/ModularizationArchitecture/7b91fb7cd2c53b46379228cac76fbbda051a26db/musicdemo/src/main/res/raw/music.mp3
--------------------------------------------------------------------------------
/musicdemo/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MusicDemo
3 |
4 |
--------------------------------------------------------------------------------
/musicdemo/src/test/java/com/spinytech/musicdemo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.musicdemo;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/picdemo/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/picdemo/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.0"
6 |
7 | defaultConfig {
8 | minSdkVersion 14
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | compile fileTree(dir: 'libs', include: ['*.jar'])
26 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
27 | exclude group: 'com.android.support', module: 'support-annotations'
28 | })
29 | compile 'com.android.support:appcompat-v7:25.1.0'
30 | testCompile 'junit:junit:4.12'
31 | compile project(':macore')
32 | }
33 |
--------------------------------------------------------------------------------
/picdemo/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/wanglei/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/picdemo/src/androidTest/java/com/spinytech/picdemo/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.picdemo;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.spinytech.picdemo.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/picdemo/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
12 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/picdemo/src/main/assets/messi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpinyTech/ModularizationArchitecture/7b91fb7cd2c53b46379228cac76fbbda051a26db/picdemo/src/main/assets/messi.png
--------------------------------------------------------------------------------
/picdemo/src/main/java/com/spinytech/picdemo/PicAction.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.picdemo;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 |
7 | import com.spinytech.macore.MaAction;
8 | import com.spinytech.macore.MaActionResult;
9 |
10 | import java.util.HashMap;
11 |
12 | /**
13 | * Created by wanglei on 2017/1/4.
14 | */
15 |
16 | public class PicAction extends MaAction {
17 | @Override
18 | public boolean isAsync(Context context, HashMap requestData) {
19 | return false;
20 | }
21 |
22 | @Override
23 | public MaActionResult invoke(Context context, HashMap requestData) {
24 | String isBigString = requestData.get("is_big");
25 | boolean isBig = "1".equals(isBigString);
26 | if(context instanceof Activity){
27 | Intent i = new Intent(context, PicActivity.class);
28 | i.putExtra("is_big",isBig);
29 | context.startActivity(i);
30 | }else{
31 | Intent i = new Intent(context, PicActivity.class);
32 | i.putExtra("is_big",isBig);
33 | i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
34 | context.startActivity(i);
35 | }
36 | return new MaActionResult.Builder().code(MaActionResult.CODE_SUCCESS).msg("success").data("").build();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/picdemo/src/main/java/com/spinytech/picdemo/PicActivity.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.picdemo;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.content.res.AssetManager;
6 | import android.graphics.Bitmap;
7 | import android.graphics.BitmapFactory;
8 | import android.os.Bundle;
9 | import android.view.Window;
10 | import android.view.WindowManager;
11 | import android.widget.ImageView;
12 |
13 | import java.io.IOException;
14 | import java.io.InputStream;
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 | public class PicActivity extends Activity {
19 |
20 | private static List oomList = new ArrayList<>();
21 |
22 | @Override
23 | protected void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
26 | WindowManager.LayoutParams.FLAG_FULLSCREEN);
27 | requestWindowFeature(Window.FEATURE_NO_TITLE);
28 | setContentView(R.layout.activity_pic);
29 | showPic();
30 | }
31 | private void showPic(){
32 | Intent intent = getIntent();
33 | if(intent!=null){
34 | boolean isBig = intent.getBooleanExtra("is_big",false);
35 | if(!isBig){
36 | ((ImageView)findViewById(R.id.pic_iv)).setImageBitmap(getImageFromAssetsFile("messi.png"));
37 | }
38 | //Do something crazy.... like OOM
39 | else{
40 | new Thread(new Runnable() {
41 | @Override
42 | public void run() {
43 | for(int i = 0;i<100;i++){
44 | oomList.add(getImageFromAssetsFile("messi.png"));
45 | }
46 | }
47 | }).start();
48 | }
49 | }
50 | }
51 |
52 | private Bitmap getImageFromAssetsFile(String fileName)
53 | {
54 | Bitmap image = null;
55 | AssetManager am = getResources().getAssets();
56 | try
57 | {
58 | InputStream is = am.open(fileName);
59 | image = BitmapFactory.decodeStream(is);
60 | is.close();
61 | }
62 | catch (IOException e)
63 | {
64 | e.printStackTrace();
65 | }
66 |
67 | return image;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/picdemo/src/main/java/com/spinytech/picdemo/PicApplicationLogic.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.picdemo;
2 |
3 | import com.spinytech.macore.multiprocess.BaseApplicationLogic;
4 | import com.spinytech.macore.router.LocalRouter;
5 |
6 | /**
7 | * Created by wanglei on 2017/1/4.
8 | */
9 |
10 | public class PicApplicationLogic extends BaseApplicationLogic {
11 |
12 | @Override
13 | public void onCreate() {
14 | super.onCreate();
15 | LocalRouter.getInstance(mApplication).registerProvider("pic",new PicProvider());
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/picdemo/src/main/java/com/spinytech/picdemo/PicProvider.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.picdemo;
2 |
3 | import com.spinytech.macore.MaProvider;
4 |
5 | /**
6 | * Created by wanglei on 2017/1/4.
7 | */
8 |
9 | public class PicProvider extends MaProvider{
10 | @Override
11 | protected void registerActions() {
12 | registerAction("pic",new PicAction());
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/picdemo/src/main/java/com/spinytech/picdemo/PicRouterConnectService.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.picdemo;
2 |
3 | import com.spinytech.macore.router.LocalRouterConnectService;
4 |
5 | /**
6 | * Created by wanglei on 2016/12/28.
7 | */
8 |
9 | public class PicRouterConnectService extends LocalRouterConnectService {
10 | }
11 |
--------------------------------------------------------------------------------
/picdemo/src/main/res/layout/activity_pic.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
--------------------------------------------------------------------------------
/picdemo/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/picdemo/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/picdemo/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Picdemo
3 |
4 |
--------------------------------------------------------------------------------
/picdemo/src/test/java/com/spinytech/picdemo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.picdemo;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':macore', ':musicdemo', ':maindemo', ':picdemo', ':webdemo'
2 |
--------------------------------------------------------------------------------
/webdemo/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/webdemo/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.0"
6 |
7 | defaultConfig {
8 | minSdkVersion 14
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | }
23 |
24 | dependencies {
25 | compile fileTree(dir: 'libs', include: ['*.jar'])
26 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
27 | exclude group: 'com.android.support', module: 'support-annotations'
28 | })
29 | compile 'com.android.support:appcompat-v7:25.1.0'
30 | testCompile 'junit:junit:4.12'
31 | compile project(':macore')
32 | }
33 |
--------------------------------------------------------------------------------
/webdemo/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/wanglei/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/webdemo/src/androidTest/java/com/spinytech/webdemo/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.webdemo;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.spinytech.webdemo.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/webdemo/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/webdemo/src/main/assets/page.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 测试网页调用
6 |
7 |
8 |
9 |
10 | LOCAL SYNC
11 |
12 | PLAY MUSIC
13 |
14 | STOP MUSIC
15 |
16 | OPEN PIC
17 |
18 |
19 |
--------------------------------------------------------------------------------
/webdemo/src/main/java/com/spinytech/webdemo/WebAction.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.webdemo;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 |
7 | import com.spinytech.macore.MaAction;
8 | import com.spinytech.macore.MaActionResult;
9 |
10 | import java.util.HashMap;
11 |
12 | /**
13 | * Created by wanglei on 2017/1/4.
14 | */
15 |
16 | public class WebAction extends MaAction {
17 | @Override
18 | public boolean isAsync(Context context, HashMap requestData) {
19 | return false;
20 | }
21 |
22 | @Override
23 | public MaActionResult invoke(Context context, HashMap requestData) {
24 | if(context instanceof Activity){
25 | Intent i = new Intent(context, WebActivity.class);
26 | context.startActivity(i);
27 | }else{
28 | Intent i = new Intent(context, WebActivity.class);
29 | i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
30 | context.startActivity(i);
31 | }
32 | return new MaActionResult.Builder().code(MaActionResult.CODE_SUCCESS).msg("success").data("").build();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/webdemo/src/main/java/com/spinytech/webdemo/WebActivity.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.webdemo;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.text.TextUtils;
6 | import android.webkit.WebSettings;
7 | import android.webkit.WebView;
8 | import android.webkit.WebViewClient;
9 |
10 | import com.spinytech.macore.MaApplication;
11 | import com.spinytech.macore.router.LocalRouter;
12 | import com.spinytech.macore.router.RouterRequest;
13 |
14 | public class WebActivity extends AppCompatActivity {
15 |
16 | private WebView mContentWv;
17 |
18 | @Override
19 | protected void onCreate(Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | setContentView(R.layout.activity_web);
22 | mContentWv = (WebView) findViewById(R.id.web);
23 | mContentWv.setWebViewClient(new MyWebViewClient());
24 | mContentWv.getSettings().setBuiltInZoomControls(true);
25 | mContentWv.getSettings().setJavaScriptEnabled(true);
26 | mContentWv.getSettings().setSupportZoom(true);
27 | mContentWv.getSettings().setUseWideViewPort(true);
28 | mContentWv.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
29 | mContentWv.getSettings().setLoadWithOverviewMode(true);
30 | mContentWv.loadUrl("file:///android_asset/page.html");
31 | }
32 |
33 |
34 | public void dispatchAction(String url) {
35 | if (url.indexOf("your_protocol://") >= 0) {
36 | String command = url.substring("your_protocol://".length());
37 | try {
38 | LocalRouter.getInstance(MaApplication.getMaApplication()).route(this, new RouterRequest.Builder(this).url(command).build());
39 | } catch (Exception e) {
40 | e.printStackTrace();
41 | }
42 | }
43 | }
44 |
45 | class MyWebViewClient extends WebViewClient {
46 | @Override
47 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
48 | if (!TextUtils.isEmpty(url) && url.startsWith("your_protocol://")) {
49 | dispatchAction(url);
50 | } else {
51 | mContentWv.loadUrl(url);
52 | }
53 | return true;
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/webdemo/src/main/java/com/spinytech/webdemo/WebApplicationLogic.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.webdemo;
2 |
3 | import com.spinytech.macore.multiprocess.BaseApplicationLogic;
4 | import com.spinytech.macore.router.LocalRouter;
5 |
6 | /**
7 | * Created by wanglei on 2017/1/4.
8 | */
9 |
10 | public class WebApplicationLogic extends BaseApplicationLogic {
11 |
12 | @Override
13 | public void onCreate() {
14 | super.onCreate();
15 | LocalRouter.getInstance(mApplication).registerProvider("web",new WebProvider());
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/webdemo/src/main/java/com/spinytech/webdemo/WebProvider.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.webdemo;
2 |
3 | import com.spinytech.macore.MaProvider;
4 |
5 | /**
6 | * Created by wanglei on 2017/1/4.
7 | */
8 |
9 | public class WebProvider extends MaProvider{
10 | @Override
11 | protected void registerActions() {
12 | registerAction("web",new WebAction());
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/webdemo/src/main/res/layout/activity_web.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/webdemo/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/webdemo/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/webdemo/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Webdemo
3 |
4 |
--------------------------------------------------------------------------------
/webdemo/src/test/java/com/spinytech/webdemo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.spinytech.webdemo;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------