├── .gitignore
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── ykbjson
│ │ │ └── app
│ │ │ └── simplepermission
│ │ │ ├── MainActivity.java
│ │ │ ├── SecondActivity.java
│ │ │ ├── TestApplication.java
│ │ │ └── TestFragment.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ ├── ic_dashboard_black_24dp.xml
│ │ ├── ic_home_black_24dp.xml
│ │ ├── ic_launcher_background.xml
│ │ └── ic_notifications_black_24dp.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── activity_second.xml
│ │ └── fragment_test.xml
│ │ ├── menu
│ │ └── navigation.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── ykbjson
│ └── app
│ └── simplepermission
│ └── ExampleUnitTest.java
├── build.gradle
├── config.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── permissionplugin
├── .gitignore
├── build.gradle
└── src
│ └── main
│ ├── groovy
│ └── com
│ │ └── ykbjson
│ │ └── lib
│ │ └── plugin
│ │ ├── SimplePermissionPlugin.groovy
│ │ ├── SimplePermissionPluginInject.groovy
│ │ └── SimplePermissionTransform.groovy
│ └── resources
│ └── META-INF
│ └── gradle-plugins
│ └── com.ykbjson.simplepermission.properties
├── settings.gradle
├── simplepermission
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── ykbjson
│ │ └── lib
│ │ └── simplepermission
│ │ ├── Permissions.java
│ │ ├── PermissionsManager.java
│ │ ├── PermissionsRequestCallback.java
│ │ └── PermissionsResultAction.java
│ └── res
│ └── values
│ └── strings.xml
└── simplepermission_ano
├── .gitignore
├── build.gradle
└── src
└── main
└── java
└── com
└── ykbjson
└── lib
└── simplepermission
└── ano
├── PermissionNotify.java
└── PermissionRequest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea
5 | .idea
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 一、SimplePermission简介
2 | 基于注解调用的Android权限申请库,无需你手写申请权限的代码,也无需你在Activity或Fragment的onRequestPermissionsResult方法里写任何代码,只需在需要申请权限的类和方法上加上对应的注解即可,简单易用。
3 |
4 | 关于本库的介绍和思路请戳
5 |
6 | [Android权限管理的探索-csdn](https://blog.csdn.net/yankebin/article/details/83863684)
7 |
8 | [Android权限管理的探索-github博客](https://ykbjson.github.io/2018/11/08/Android%E6%9D%83%E9%99%90%E7%AE%A1%E7%90%86%E7%9A%84%E6%8E%A2%E7%B4%A2/)
9 |
10 | # 二、如何引用
11 | 因为这个功能是基于gradle插件来实现的,所以和一般权限库有所不同,需要在你的工程根目录的build.gradle文件相似位置里加上如下代码(看有注释的地方)。当前最新版本为
12 | [  ](https://bintray.com/ykbjson/maven/simplepermissionplugin/_latestVersion)
13 |
14 |
15 |
16 | buildscript {
17 | repositories {
18 | google()
19 | jcenter()
20 | mavenCentral()
21 | mavenLocal()
22 | //这是我bintray的maven地址
23 | maven { url 'https://dl.bintray.com/ykbjson/maven' }
24 | }
25 | dependencies {
26 | classpath 'com.android.tools.build:gradle:3.1.1'
27 | //这是simplepermissionplugin的classpath
28 | classpath 'com.ykbjson.simplepermission:simplepermissionplugin:1.0.1'
29 | }
30 | }
31 |
32 |
33 | allprojects {
34 | repositories {
35 | google()
36 | jcenter()
37 | mavenCentral()
38 | mavenLocal()
39 | //这是我bintray的maven地址
40 | maven { url 'https://dl.bintray.com/ykbjson/maven' }
41 | }
42 | }
43 |
44 |
45 |
46 | 然后在app module的build.gradle文件里引入apply simplepermissionplugin插件
47 |
48 |
49 |
50 | apply plugin: 'com.ykbjson.simplepermission'
51 |
52 |
53 |
54 | 最后在app module的build.gradle文件里引入simpleprmission库和simplepermission_ano库,即可大功告成
55 |
56 |
57 |
58 | implementation 'com.ykbjson.simplepermission:simplepermission:1.0.1'
59 | implementation 'com.ykbjson.simplepermission:simplepermission_ano:1.0.0'
60 |
61 |
62 |
63 | # 三、如何使用
64 |
65 | 使用非常简单。
66 | 首先,在需要申请权限的Activity或Fragment类上加上注解@PermissionNotify
67 |
68 |
69 |
70 | @PermissionNotify
71 | public class MainActivity extends AppCompatActivity implements View.OnClickListener
72 | private TextView mTextMessage;
73 | protected void onCreate(Bundle savedInstanceState) {
74 | super.onCreate(savedInstanceState);
75 | setContentView(R.layout.activity_main);
76 | mTextMessage = (TextView) findViewById(R.id.message);
77 |
78 | mTextMessage.setOnClickListener(this);
79 | }
80 |
81 | private void setText(final String text) {
82 | mTextMessage.setText(text);
83 | }
84 |
85 | @Override
86 | public void onClick(View v) {
87 | setText("哈哈哈哈哈哈");
88 | }
89 | }
90 |
91 |
92 |
93 | 然后在Activity或Fragment的某个方法上加上注解@PermissionRequest
94 |
95 |
96 |
97 |
98 | @PermissionRequest(
99 | requestCode = 10010,
100 | requestPermissions = {Manifest.permission.ACCESS_FINE_LOCATION,
101 | Manifest.permission.ACCESS_COARSE_LOCATION,
102 | Manifest.permission.READ_CONTACTS}
103 | ,needReCall = true
104 | )
105 | private void setText(String text) {
106 | mTextMessage.setText(text);
107 | }
108 |
109 |
110 |
111 | 然后。。。。。。结束啦!!!!编译结束后其实MainActivity里的代码大致会变成如下的样子
112 |
113 |
114 |
115 | @PermissionNotify
116 | public class MainActivity extends AppCompatActivity implements OnClickListener, PermissionsRequestCallback {
117 | private TextView mTextMessage;
118 | private final Map requestPermissionMethodParams = new HashMap();
119 |
120 | public MainActivity() {
121 | }
122 |
123 | protected void onCreate(Bundle savedInstanceState) {
124 | super.onCreate(savedInstanceState);
125 | this.setContentView(2131361818);
126 |
127 | this.mTextMessage.setOnClickListener(this);
128 | }
129 |
130 | @PermissionRequest(
131 | requestCode = 10010,
132 | requestPermissions = {"android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_COARSE_LOCATION", "android.permission.READ_CONTACTS"},
133 | needReCall = true
134 | )
135 | private void setText(String text) {
136 | String[] var2 = new String[]{"android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_COARSE_LOCATION", "android.permission.READ_CONTACTS"};
137 | boolean var3 = PermissionsManager.getInstance().hasAllPermissions(this, var2);
138 | if (!var3) {
139 | ArrayList var4 = new ArrayList();
140 | var4.add(text);
141 | this.requestPermissionMethodParams.put(10010, var4);
142 | PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(10010, this, var2, this);
143 | } else {
144 | this.mTextMessage.setText(text);
145 | }
146 | }
147 |
148 | public void onClick(View v) {
149 | this.setText("哈哈哈哈哈哈");
150 | }
151 |
152 | public void onGranted(int var1, String var2) {
153 | }
154 |
155 | public void onDenied(int var1, String var2) {
156 | }
157 |
158 | public void onDeniedForever(int var1, String var2) {
159 | }
160 |
161 | public void onFailure(int var1, String[] var2) {
162 | }
163 |
164 | public void onSuccess(int var1) {
165 | Object var2 = this.requestPermissionMethodParams.get(var1);
166 | if (var1 == 10010) {
167 | this.setText((String)((List)var2).get(0));
168 | }
169 | }
170 |
171 | public void onRequestPermissionsResult(int var1, String[] var2, int[] var3) {
172 | PermissionsManager.getInstance().notifyPermissionsChange(var2, var3);
173 | super.onRequestPermissionsResult(var1, var2, var3);
174 | }
175 | }
176 |
177 |
178 |
179 |
180 |
181 |
182 | 当然,如果你觉得使用注解会有诸多限制(请看下面第四条提到的“一些限制”),你也可以直接使用simplepermission库来实现权限的申请,类似代码如下
183 |
184 |
185 |
186 |
187 | private void setText(final String text) {
188 | PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(0, this,
189 | new String[]{Manifest.permission.READ_CONTACTS}, new PermissionsRequestCallback() {
190 | @Override
191 | public void onGranted(int requestCode, String permission) {
192 |
193 | }
194 |
195 | @Override
196 | public void onDenied(int requestCode, String permission) {
197 |
198 | }
199 |
200 | @Override
201 | public void onDeniedForever(int requestCode, String permission) {
202 |
203 | }
204 |
205 | @Override
206 | public void onFailure(int requestCode, String[] deniedPermissions) {
207 |
208 | }
209 |
210 | @Override
211 | public void onSuccess(int requestCode) {
212 | mTextMessage.setText(text);
213 | }
214 | });
215 | }
216 |
217 |
218 |
219 | Android M及以上版本,需要在Activit或Fragment重载onRequestPermissionsResult方法,并且在该方法内部加入PermissionsManager.getInstance().notifyPermissionsChange(permissions,grantResults),类似如下代码
220 |
221 |
222 |
223 | @Override
224 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
225 | PermissionsManager.getInstance().notifyPermissionsChange(permissions,grantResults);
226 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
227 | }
228 |
229 |
230 |
231 |
232 | # 四、一些限制
233 |
234 | ##### 4.1 由于本人能力有限,本库目前还不支持在“带返回值”的方法上去加@PermissionRequest注解并且@PermissionRequest的needRecall设置为true,当然,needRecall设置为false时,是支持的。因为本库的原理是这样的:添加了@PermissionRequest注解的方法,我会先判断当前程序是否已经有了@PermissionRequest的requestPermissions里包含的权限,如果没有,则插入申请权限的代码,如果@PermissionRequest的needRecall为true,则需要存储方法的参数,以备权限回调成功的时候在调用此方法,然后插入“return”,结束方法执行;如果@PermissionRequest的needRecall为false,则这里只插入申请权限的代码,不在干预此方法的后续逻辑。
235 |
236 | ##### 4.2 本库目前还不支持在内部类里面的方法上加@PermissionRequest注解,因为permission权限申请库必要的一个参数是Activit或Fragment,如果是在内部类里面使用,我目前还无法得知如何获取该内部类持有的Activit或Fragment,尤其是在多层内部类嵌套的时候。
237 |
238 | ##### 4.3 本库目前还不支持在static方法上添加@PermissionRequest注解,因为用javassit插入“MainActivity.this”类似语句会报错,我暂时还没找到解决办法
239 |
240 | ##### 4.4 本库因为修改了class文件插入了一些代码,很有可能会使应用程序出现multiDex异常,所以,在需要的时候,最好让你的程序支持multiDex
241 |
242 | ##### 4.5 多个添加了@PermissionRequest注解的方法的requestCode千万不要相同,不然在权限申请成功回调的地方获取申请权限方法的参数会出现问题,导致你的程序会出现一些无法预知的错误
243 |
244 | ## License
245 |
246 |
247 |
248 | Copyright 2018 ykbjson
249 |
250 | Licensed under the Apache License, Version 2.0 (the "License");
251 | you may not use this file except in compliance with the License.
252 | You may obtain a copy of the License at
253 |
254 | http://www.apache.org/licenses/LICENSE-2.0
255 |
256 | Unless required by applicable law or agreed to in writing, software
257 | distributed under the License is distributed on an "AS IS" BASIS,
258 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
259 | See the License for the specific language governing permissions and
260 | limitations under the License.
261 |
262 |
263 |
264 |
265 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | //com.hc.gradle为resources/META-INF/gradle-plugins
3 | //permissionplugin下的properties文件名称
4 | //apply plugin: 'com.ykbjson.simplepermission'
5 |
6 | android {
7 | compileSdkVersion 27
8 | defaultConfig {
9 | applicationId "com.ykbjson.app.simplepermission"
10 | minSdkVersion 17
11 | targetSdkVersion 27
12 | versionCode 1
13 | versionName "1.0"
14 | multiDexEnabled = true
15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(dir: 'libs', include: ['*.jar'])
27 | // implementation 'com.ykbjson.simplepermission:simplepermission:1.0.1'
28 | // implementation 'com.ykbjson.simplepermission:simplepermission_ano:1.0.0'
29 |
30 | implementation project(':simplepermission')
31 | implementation project(':simplepermission_ano')
32 |
33 | implementation 'com.android.support:appcompat-v7:27.0.2'
34 | implementation 'com.android.support:design:27.0.2'
35 | implementation 'com.android.support.constraint:constraint-layout:1.0.2'
36 | implementation 'com.android.support:support-vector-drawable:27.0.2'
37 | implementation 'com.android.support:multidex:1.0.1'
38 | testImplementation 'junit:junit:4.12'
39 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
40 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ykbjson/app/simplepermission/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.ykbjson.app.simplepermission;
2 |
3 | import android.Manifest;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.annotation.NonNull;
7 | import android.support.design.widget.BottomNavigationView;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.view.MenuItem;
10 | import android.view.View;
11 | import android.widget.TextView;
12 |
13 | import com.ykbjson.lib.simplepermission.ano.PermissionNotify;
14 | import com.ykbjson.lib.simplepermission.ano.PermissionRequest;
15 |
16 | @PermissionNotify
17 | public class MainActivity extends AppCompatActivity implements View.OnClickListener {
18 |
19 | private TextView mTextMessage;
20 |
21 | private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
22 | = new BottomNavigationView.OnNavigationItemSelectedListener() {
23 |
24 | @Override
25 | public boolean onNavigationItemSelected(@NonNull MenuItem item) {
26 | switch (item.getItemId()) {
27 | case R.id.navigation_home:
28 | mTextMessage.setText(R.string.title_home);
29 | return true;
30 | case R.id.navigation_dashboard:
31 | mTextMessage.setText(R.string.title_dashboard);
32 | return true;
33 | case R.id.navigation_notifications:
34 | mTextMessage.setText(R.string.title_notifications);
35 | return true;
36 | }
37 | return false;
38 | }
39 | };
40 |
41 | @Override
42 | protected void onCreate(final Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.activity_main);
45 | mTextMessage = (TextView) findViewById(R.id.message);
46 | BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
47 | navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
48 |
49 | mTextMessage.setOnClickListener(this);
50 | }
51 |
52 | @PermissionRequest(
53 | requestCode = 10010,
54 | requestPermissions = {Manifest.permission.ACCESS_FINE_LOCATION,
55 | Manifest.permission.ACCESS_COARSE_LOCATION,
56 | Manifest.permission.READ_CONTACTS}
57 | ,needReCall = true
58 | )
59 | private void setText(final String text) {
60 | startActivity(new Intent(this,SecondActivity.class).putExtra("text",text));
61 | }
62 |
63 | @Override
64 | public void onClick(View v) {
65 | setText("哈哈哈哈哈哈");
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ykbjson/app/simplepermission/SecondActivity.java:
--------------------------------------------------------------------------------
1 | package com.ykbjson.app.simplepermission;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.support.v7.app.AppCompatActivity;
6 |
7 | public class SecondActivity extends AppCompatActivity {
8 |
9 | @Override
10 | protected void onCreate(Bundle savedInstanceState) {
11 | super.onCreate(savedInstanceState);
12 | setContentView(R.layout.activity_second);
13 | getSupportFragmentManager().beginTransaction().replace(R.id.container, Fragment.instantiate(this, TestFragment.class.getName(), getIntent().getExtras()))
14 | .commit();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ykbjson/app/simplepermission/TestApplication.java:
--------------------------------------------------------------------------------
1 | package com.ykbjson.app.simplepermission;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import android.support.multidex.MultiDex;
6 |
7 | /**
8 | * Description:
9 | * Creator:yankebin
10 | * CreatedAt:2018/10/29
11 | */
12 | public class TestApplication extends Application {
13 | @Override
14 | protected void attachBaseContext(Context base) {
15 | super.attachBaseContext(base);
16 | MultiDex.install(base);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ykbjson/app/simplepermission/TestFragment.java:
--------------------------------------------------------------------------------
1 | package com.ykbjson.app.simplepermission;
2 |
3 | import android.Manifest;
4 | import android.os.Bundle;
5 | import android.support.annotation.NonNull;
6 | import android.support.annotation.Nullable;
7 | import android.support.v4.app.Fragment;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.TextView;
12 | import android.widget.Toast;
13 |
14 | import com.ykbjson.lib.simplepermission.ano.PermissionNotify;
15 | import com.ykbjson.lib.simplepermission.ano.PermissionRequest;
16 |
17 | /**
18 | * Description:
19 | * Creator:yankebin
20 | * CreatedAt:2018/11/8
21 | */
22 | @PermissionNotify
23 | public class TestFragment extends Fragment {
24 | private TextView mTextMessage;
25 |
26 |
27 | @Nullable
28 | @Override
29 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
30 | View view = inflater.inflate(R.layout.fragment_test, container, false);
31 | mTextMessage = view.findViewById(R.id.message);
32 | return view;
33 | }
34 |
35 | @Override
36 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
37 | super.onViewCreated(view, savedInstanceState);
38 | mTextMessage.setText(getArguments().getString("text"));
39 | test();
40 | }
41 |
42 | @PermissionRequest(
43 | requestCode = 100,
44 | requestPermissions = {Manifest.permission.READ_SMS},
45 | needReCall = true)
46 | private void test() {
47 | Toast.makeText(getActivity(), "呵呵呵呵呵", Toast.LENGTH_LONG).show();
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_dashboard_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_home_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_notifications_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
20 |
21 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_second.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_test.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaertj/SimplePermission/acf72140da4d59eb5e0a6f2c2fad716ae7b858e3/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaertj/SimplePermission/acf72140da4d59eb5e0a6f2c2fad716ae7b858e3/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaertj/SimplePermission/acf72140da4d59eb5e0a6f2c2fad716ae7b858e3/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaertj/SimplePermission/acf72140da4d59eb5e0a6f2c2fad716ae7b858e3/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaertj/SimplePermission/acf72140da4d59eb5e0a6f2c2fad716ae7b858e3/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaertj/SimplePermission/acf72140da4d59eb5e0a6f2c2fad716ae7b858e3/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaertj/SimplePermission/acf72140da4d59eb5e0a6f2c2fad716ae7b858e3/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaertj/SimplePermission/acf72140da4d59eb5e0a6f2c2fad716ae7b858e3/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaertj/SimplePermission/acf72140da4d59eb5e0a6f2c2fad716ae7b858e3/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaertj/SimplePermission/acf72140da4d59eb5e0a6f2c2fad716ae7b858e3/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | SimplePermission
3 | Home
4 | Dashboard
5 | Notifications
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/ykbjson/app/simplepermission/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.ykbjson.app.simplepermission;
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() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | apply from: "config.gradle"
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | mavenCentral()
9 | mavenLocal()
10 | maven {//本地Maven仓库地址
11 | url uri('/Users/yanan/Desktop/android_project/mavenlocal/')
12 | }
13 | maven { url 'https://dl.bintray.com/ykbjson/maven' }
14 | }
15 | dependencies {
16 | classpath 'com.android.tools.build:gradle:3.1.1'
17 | // classpath 'com.ykbjson.simplepermission:simplepermissionplugin:1.0.1'
18 | classpath 'com.novoda:bintray-release:0.8.1'
19 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
20 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
21 | // NOTE: Do not place your application dependencies here; they belong
22 | // in the individual module build.gradle files
23 | }
24 | }
25 |
26 | allprojects {
27 | repositories {
28 | google()
29 | jcenter()
30 | mavenCentral()
31 | mavenLocal()
32 | maven {//本地Maven仓库地址
33 | url uri('/Users/yanan/Desktop/android_project/mavenlocal/')
34 | }
35 | maven { url 'https://dl.bintray.com/ykbjson/maven' }
36 | }
37 | }
38 |
39 | task clean(type: Delete) {
40 | delete rootProject.buildDir
41 | }
42 |
43 | // 指定javadoc UTF-8格式
44 | task javadoc(type: Javadoc) {
45 | options{
46 | encoding "UTF-8"
47 | charSet 'UTF-8'
48 | links "http://docs.oracle.com/javase/7/docs/api"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/config.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 | plugins = [
3 | library : 'com.android.library',
4 | application: 'com.android.application',
5 | maven : 'com.github.dcendents.android-maven',
6 | bintray : 'com.jfrog.bintray',
7 | apt : 'com.neenbedankt.android-apt'
8 | ]
9 |
10 | android = [
11 | applicationId : 'com.ykbjson.app.simplepermission',
12 | compileSdkVersion: 27,
13 | buildToolsVersion: '27.0.3',
14 |
15 | minSdkVersion : 17,
16 | targetSdkVersion : 27,
17 |
18 | versionCode : 100,
19 | versionName : '1.0.0',
20 | ]
21 |
22 | bintray = [
23 | plugVersion : '1.0.1',
24 | anoVersion : '1.0.0',
25 | libraryVersion: '1.0.1',
26 |
27 | siteUrl : 'https://github.com/ykbjson/SimplePermission',
28 | gitUrl : 'https://github.com/ykbjson/SimplePermission.git',
29 |
30 | group : 'com.ykbjson.simplepermission',
31 |
32 | // project
33 | packaging : 'aar',
34 | name : 'SimplePermission',
35 | description : 'SimplePermission For Android',
36 |
37 | // project.license
38 | licenseName : 'The Apache Software License, Version 2.0',
39 | licenseUrl : 'http://www.apache.org/licenses/LICENSE-2.0.txt',
40 |
41 | // project.developers
42 | developerId : 'ykbjson',
43 | developerName : 'ykbjson',
44 | developerEmail: 'ykbdevelop@gmail.com',
45 |
46 | // bintray
47 | binrayLibrary : "simplepermission",
48 | bintrayRepo : "maven",
49 | bintrayUser : 'ykbjson',
50 | bintrayLicense: "Apache-2.0"
51 | ]
52 | def rxBindingVersion = '2.1.1'
53 | def androidVersion = "27.0.2"
54 | dependencies = [
55 | supportV4 : "com.android.support:support-v4:$androidVersion",
56 | appCompat : "com.android.support:appcompat-v7:$androidVersion",
57 | design : "com.android.support:design:$androidVersion",
58 | cardView : "com.android.support:cardview-v7:$androidVersion",
59 | recyclerView : "com.android.support:recyclerview-v7:$androidVersion",
60 | supportAnnotations : "com.android.support:support-annotations:$androidVersion",
61 | supportMultidex : 'com.android.support:multidex:1.0.1',
62 |
63 | loading : 'com.yanzhenjie:loading:1.0.2',
64 | swipeRecyclerView : 'com.yanzhenjie:recyclerview-swipe:1.1.3',
65 |
66 | RxBinding : "com.jakewharton.rxbinding2:rxbinding:$rxBindingVersion",
67 | RxBindingSupportV4 : "com.jakewharton.rxbinding2:rxbinding-support-v4:$rxBindingVersion",
68 | RxBindingAppcompatV7 : "com.jakewharton.rxbinding2:rxbinding-appcompat-v7:$rxBindingVersion",
69 | RxBindingRecycleViewV7: "com.jakewharton.rxbinding2:rxbinding-recyclerview-v7:$rxBindingVersion",
70 | RxBindingDesign : "com.jakewharton.rxbinding2:rxbinding-design:$rxBindingVersion",
71 | RxBindingLeanBackv17 : "com.jakewharton.rxbinding2:rxbinding-leanback-v17:$rxBindingVersion",
72 |
73 | //rest+rxAndroid
74 | RXAndroid : 'io.reactivex.rxjava2:rxandroid:2.0.2',
75 | RXJava : 'io.reactivex.rxjava2:rxjava:2.1.11',
76 | // Retrofit2
77 | retrofit2 : 'com.squareup.retrofit2:retrofit:2.4.0',
78 | // Retrofit2适配RxJava
79 | retrofit2RXJavaAdapter: 'com.squareup.retrofit2:adapter-rxjava:2.4.0',
80 | // Retrofit2 Gson数据转换器
81 | retrofit2GsonConverter: 'com.squareup.retrofit2:converter-gson:2.4.0',
82 | // Retrofit2日志拦截器
83 | retrofit2Interceptor : 'com.squareup.okhttp3:logging-interceptor:3.10.0',
84 |
85 | glide : 'com.github.bumptech.glide:glide:3.7.0',
86 | //下拉刷新
87 | ultraptr : 'in.srain.cube:ultra-ptr:1.0.11',
88 | //ViewHelper
89 | nineoldandroids : 'com.nineoldandroids:library:2.4.0',
90 | //photoview
91 | photoview : 'com.github.chrisbanes.photoview:library:1.2.4',
92 | //圆角
93 | roundedimageview : 'com.makeramen:roundedimageview:2.2.1',
94 | //圆形图像
95 | circleimageview : 'de.hdodenhof:circleimageview:2.0.0',
96 | //上传图片
97 | upyun : 'com.upyun:upyun-android-sdk:2.0.4',
98 | //权限库
99 | permissiongen : 'com.lovedise:permissiongen:0.0.6',
100 | //图片选择器
101 | picasso : 'com.squareup.picasso:picasso:2.4.0',
102 | //okhttp-urlconnection
103 | okhttpUrlconnection : 'com.squareup.okhttp:okhttp-urlconnection:1.6.0',
104 | //bus
105 | xbus : 'com.mcxiaoke.xbus:bus:1.0.1',
106 | //sweetDialog
107 | sweetalert : 'cn.pedant.sweetalert:library:1.3',
108 | //OKHTTP
109 | okhttp3 : 'com.squareup.okhttp3:okhttp:3.10.0',
110 | //imageloader
111 | imageloader : 'com.nostra13.universalimageloader:universal-image-loader:1.9.5',
112 | //tablayout
113 | tablayout : 'com.flyco.tablayout:FlycoTabLayout_Lib:2.0.8@aar',
114 | //富文本查看器
115 | richtext : 'com.zzhoujay.richtext:richtext:2.3.7',
116 | //FlycoDialog
117 | FlycoDialog : 'com.flyco.dialog:FlycoDialog_Lib:1.2.6@aar',
118 | //阻尼效果
119 | overscroll : 'me.everything:overscroll-decor-android:1.0.1',
120 | //进度条
121 | RoundCornerProgressBar: 'com.akexorcist:RoundCornerProgressBar:2.0.3',
122 | //标签
123 | tagcloudview : 'com.github.kingideayou:tagcloudview:1.0.2',
124 | //热补丁修复框架tinker
125 | tinker : 'com.tencent.tinker:tinker-android-lib:1.9.1',
126 | tinkerAnno : 'com.tencent.tinker:tinker-android-anno:1.9.1',
127 | //growingio
128 | growingio : 'com.growingio.android:vds-android-agent:0.9.103@aar',
129 | //标签2
130 | androidtagview : 'co.lujun:androidtagview:1.0.6',
131 | //butterknife
132 | butterknife : 'com.jakewharton:butterknife:8.8.1',
133 | //图片选择器
134 | PictureSelector : 'com.github.LuckSiege.PictureSelector:picture_library:v2.1.0',
135 |
136 |
137 | fastjson : 'com.alibaba:fastjson:1.1.57.android',
138 | gson : 'com.google.code.gson:gson:2.8.2',
139 |
140 | ]
141 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx6656m
10 | android.useDexArchive= true
11 | # When configured, Gradle will run in incubating parallel mode.
12 | # This option should only be used with decoupled projects. More details, visit
13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
14 | # org.gradle.parallel=true
15 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javaertj/SimplePermission/acf72140da4d59eb5e0a6f2c2fad716ae7b858e3/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/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 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
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 Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/permissionplugin/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/permissionplugin/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'groovy'
2 | apply plugin: 'com.novoda.bintray-release'
3 | apply plugin: 'maven'
4 |
5 | //加载资源
6 | Properties properties = new Properties()
7 | InputStream inputStream = project.rootProject.file('local.properties').newDataInputStream()
8 | properties.load(inputStream)
9 |
10 | publish {
11 | bintrayUser = properties.getProperty("bintrayUser")
12 | bintrayKey = properties.getProperty("bintrayKey")
13 | userOrg = 'ykbjson' // bintray注册的用户名
14 | groupId = rootProject.ext.bintray.group
15 | artifactId = 'simplepermissionplugin'// bintray创建的package
16 | publishVersion = rootProject.ext.bintray.plugVersion
17 | desc = 'SimplePermission权限申请库自动生成代码gradle插件'
18 | }
19 |
20 | compileGroovy {
21 | sourceCompatibility = 1.7
22 | targetCompatibility = 1.7
23 | }
24 |
25 | //group和version
26 | group=rootProject.ext.bintray.group
27 | version=rootProject.ext.bintray.plugVersion
28 |
29 | //打包到本地或者远程Maven库
30 | //uploadArchives {
31 | // repositories {
32 | // mavenDeployer {
33 | // //提交到远程服务器:
34 | // // repository(url: "http://www.xxx.com/repos") {
35 | // // authentication(userName: "admin", password: "admin")
36 | // // }
37 | // //本地的Maven地址设置为E:/Maven
38 | // repository(url: uri('/Users/yanan/Desktop/android_project/mavenlocal/'))
39 | // }
40 | // }
41 | //}
42 |
43 | dependencies {
44 | //gradle sdk
45 | implementation gradleApi()
46 | //groovy sdk
47 | implementation localGroovy()
48 | implementation project(':simplepermission_ano')
49 | // compile 'com.ykbjson.simplepermission:simplepermission_ano:1.0.0'
50 | implementation 'com.android.tools.build:gradle:3.1.1'
51 | implementation 'org.javassist:javassist:3.23.0-GA'
52 | }
53 |
54 | repositories {
55 | mavenCentral()
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/permissionplugin/src/main/groovy/com/ykbjson/lib/plugin/SimplePermissionPlugin.groovy:
--------------------------------------------------------------------------------
1 | package com.ykbjson.lib.plugin
2 |
3 | import com.android.build.gradle.AppExtension
4 | import org.gradle.api.Plugin
5 | import org.gradle.api.Project
6 |
7 | public class SimplePermissionPlugin implements Plugin {
8 |
9 | @Override
10 | void apply(Project project) {
11 | System.out.println("======================================================")
12 | System.out.println("= welcome to simple permission gradle plugin! =")
13 | System.out.println("======================================================")
14 | //注册SimplePermissionTransform
15 | def android = project.extensions.findByType(AppExtension)
16 | def classTransform = new SimplePermissionTransform(project)
17 | android.registerTransform(classTransform)
18 | }
19 | }
--------------------------------------------------------------------------------
/permissionplugin/src/main/groovy/com/ykbjson/lib/plugin/SimplePermissionPluginInject.groovy:
--------------------------------------------------------------------------------
1 | package com.ykbjson.lib.plugin
2 |
3 | import com.ykbjson.lib.simplepermission.ano.PermissionNotify
4 | import com.ykbjson.lib.simplepermission.ano.PermissionRequest
5 | import javassist.*
6 | import org.gradle.api.Project
7 |
8 | public class SimplePermissionPluginInject {
9 |
10 | private static final ClassPool pool = ClassPool.getDefault()
11 |
12 | private static final String PACKAGE_STAT = "com"
13 | private static final int CLASS_LENGTH = ".class".length() //6
14 | private static final String INJECT_PERMISSION_NOTIFY_METHOD_NAME = "onRequestPermissionsResult"
15 | private static
16 | final String INJECT_PERMISSION_REQUEST_METHOD_PARAMS_FIELD_NAME = "requestPermissionMethodParams"
17 | private static
18 | final String PERMISSIONS_MANAGER_PATH = "com.ykbjson.lib.simplepermission.PermissionsManager"
19 | private static
20 | final String PERMISSIONS_PATH = "com.ykbjson.lib.simplepermission.Permissions"
21 | private static
22 | final String PERMISSIONS_REQUEST_CALLBACK_PATH = "com.ykbjson.lib.simplepermission.PermissionsRequestCallback"
23 | private static
24 | final String PERMISSIONS_RESULT_ACTION_PATH = "com.ykbjson.lib.simplepermission.PermissionsResultAction"
25 | //添加成员变量存储需要请求权限的方法的参数信息
26 | private static
27 | final String REQUEST_PERMISSION_METHOD_PARAMS_INJECT_CONTENT = "private final Map requestPermissionMethodParams = new HashMap();"
28 | private static
29 | final String PERMISSIONS_REQUEST_CALLBACK_METHOD_ONGRANTED = "public void onGranted(int requestCode,String permission){ }\n"
30 | private static
31 | final String PERMISSIONS_REQUEST_CALLBACK_METHOD_ONDENIED = "public void onDenied(int requestCode,String permission){ }\n"
32 | private static
33 | final String PERMISSIONS_REQUEST_CALLBACK_METHOD_ONDENIED_FOREVER = "public void onDeniedForever(int requestCode,String permission){ }\n"
34 | private static
35 | final String PERMISSIONS_REQUEST_CALLBACK_METHOD_ONFAILURE = "public void onFailure(int requestCode,String[] deniedPermissions){ }\n"
36 | private static
37 | final String PERMISSIONS_REQUEST_CALLBACK_METHOD_ONSUCCESS = "public void onSuccess(int requestCode){ }\n"
38 |
39 | private static final String[] PERMISSIONS_REQUEST_CALLBACK_METHODS = [
40 | PERMISSIONS_REQUEST_CALLBACK_METHOD_ONGRANTED,
41 | PERMISSIONS_REQUEST_CALLBACK_METHOD_ONDENIED,
42 | PERMISSIONS_REQUEST_CALLBACK_METHOD_ONDENIED_FOREVER,
43 | PERMISSIONS_REQUEST_CALLBACK_METHOD_ONFAILURE,
44 | PERMISSIONS_REQUEST_CALLBACK_METHOD_ONSUCCESS
45 | ]
46 |
47 | private static
48 | final String INJECT_PERMISSION_NOTIFY_CONTENT = "PermissionsManager.getInstance().notifyPermissionsChange(permissions,grantResults);\n"
49 |
50 | private static final String ACTIVITY_PATH = "android.app.Activity"
51 |
52 | private static final String FRAGMENT_PATH = "android.app.Fragment"
53 |
54 | private static final String V4_FRAGMENT_PATH = "android.support.v4.app.Fragment"
55 |
56 | static def classPathList = new ArrayList()
57 |
58 | public static void removeClassPath(Project project) {
59 | if (classPathList != null && !classPathList.isEmpty()) {
60 | classPathList.each {
61 | try {
62 | pool.removeClassPath(it)
63 | } catch (Exception e) {
64 | project.logger.error(e.getMessage())
65 | }
66 | }
67 | classPathList.clear()
68 | }
69 | pool.clearImportedPackages()
70 | }
71 |
72 | public static void injectJar(Project project, String path, String packageName) {
73 | def classPath = new JarClassPath(path)
74 | pool.appendClassPath(classPath)
75 | classPathList.add(classPath)
76 | //project.android.bootClasspath 加入android.jar,否则找不到android相关的所有类
77 | pool.appendClassPath(project.android.bootClasspath[0].toString())
78 | }
79 |
80 | public static void injectDir(Project project, String path, String packageName) {
81 | //将当前路径加入类池,不然找不到这个类
82 | pool.appendClassPath(path)
83 | //project.android.bootClasspath 加入android.jar,不然找不到android相关的所有类
84 | pool.appendClassPath(project.android.bootClasspath[0].toString())
85 | //引入com.ykbjson.lib.simplepermission下面要使用到的类
86 | pool.importPackage(PERMISSIONS_MANAGER_PATH)
87 | pool.importPackage(PERMISSIONS_PATH)
88 | pool.importPackage(PERMISSIONS_RESULT_ACTION_PATH)
89 | pool.importPackage(PERMISSIONS_REQUEST_CALLBACK_PATH)
90 | pool.importPackage(ACTIVITY_PATH)
91 | pool.importPackage(FRAGMENT_PATH)
92 | pool.importPackage(V4_FRAGMENT_PATH)
93 | pool.importPackage("java.util.Map")
94 | pool.importPackage("java.util.HashMap")
95 | pool.importPackage("java.util.List")
96 | pool.importPackage("java.util.ArrayList")
97 |
98 | File dir = new File(path)
99 | if (!dir.isDirectory()) {
100 | return
101 | }
102 | dir.eachFileRecurse { File file ->
103 | String filePath = file.absolutePath
104 | //确保当前文件是class文件,并且不是系统自动生成的class文件
105 | if (!filePath.endsWith(".class")
106 | || filePath.contains('R$')
107 | || filePath.contains('R.class')
108 | || filePath.contains("BuildConfig.class")) {
109 | return
110 | }
111 | project.logger.warn "SimplePermission-----> filePath : " + filePath
112 | int index = filePath.indexOf(PACKAGE_STAT)
113 | int end = filePath.length() - CLASS_LENGTH // .class = 6
114 | String className = filePath.substring(index, end)
115 | .replace('\\', '.').replace('/', '.')
116 | project.logger.warn "SimplePermission-----> className : " + className
117 | if (null == className || "" == className || className.contains("\$")) {
118 | return
119 | }
120 | CtClass c = pool.getCtClass(className)
121 | //检验注解
122 | if (!c.hasAnnotation(PermissionNotify.class)) {
123 | return
124 | }
125 | //不是activity或fragment不处理
126 | if (!c.subclassOf(pool.get(ACTIVITY_PATH)) && !c.subclassOf(pool.get(FRAGMENT_PATH)) && !c.subclassOf(pool.get(V4_FRAGMENT_PATH))) {
127 | return
128 | }
129 | try {
130 | //找到需要修改的class,开始修改class文件,先解冻
131 | if (c.isFrozen()) {
132 | c.defrost()
133 | }
134 | //校验是否实现了PermissionsRequestCallback接口,没有实现则让其实现该接口,并重载相关方法
135 | if (null == c.getInterfaces() || !c.getInterfaces().contains(pool.get(PERMISSIONS_REQUEST_CALLBACK_PATH))) {
136 | c.addInterface(pool.get(PERMISSIONS_REQUEST_CALLBACK_PATH))
137 | //重载方法
138 | for (String methodStr : PERMISSIONS_REQUEST_CALLBACK_METHODS) {
139 | project.logger.warn "SimplePermission-----> override PermissionsRequestCallback method : " + methodStr
140 | CtMethod overrideMethod = CtNewMethod.make(methodStr, c)
141 | c.addMethod(overrideMethod)
142 | }
143 | }
144 | //加入存储方法的map结构
145 | CtField requestPermissionMethodParamsField = findFieldByName(c, INJECT_PERMISSION_REQUEST_METHOD_PARAMS_FIELD_NAME)
146 | if (null == requestPermissionMethodParamsField) {
147 | requestPermissionMethodParamsField = CtField.make(REQUEST_PERMISSION_METHOD_PARAMS_INJECT_CONTENT, c)
148 | c.addField(requestPermissionMethodParamsField)
149 | }
150 | //检测Activity或Fragment是否声明或重写了onRequestPermissionsResult方法
151 | CtMethod notifyMethod = findMethodByName(c, INJECT_PERMISSION_NOTIFY_METHOD_NAME)
152 | //如果已经重写,则在super之前插入代码
153 | if (null != notifyMethod) {
154 | project.logger.error "SimplePermission-----> find notifyPermission method : " + notifyMethod.longName
155 | project.logger.error "SimplePermission-----> notifyPermission method insert content :\n" + INJECT_PERMISSION_NOTIFY_CONTENT
156 | notifyMethod.insertBefore(INJECT_PERMISSION_NOTIFY_CONTENT)
157 | } else {
158 | //没有重写,插入重载该方法的代码
159 | StringBuilder methodBuilder = new StringBuilder()
160 | .append("public void ")
161 | .append(INJECT_PERMISSION_NOTIFY_METHOD_NAME)
162 | .append("(")
163 | .append("int requestCode, ")
164 | .append("String[] permissions, ")
165 | .append("int[] grantResults) { \n")
166 | .append(INJECT_PERMISSION_NOTIFY_CONTENT)
167 | .append("super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n")
168 | .append("}")
169 | project.logger.error "SimplePermission-----> add notifyPermission method :\n " + methodBuilder.toString()
170 |
171 | notifyMethod = CtNewMethod.make(methodBuilder.toString(), c)
172 | c.addMethod(notifyMethod)
173 | }
174 | //在加了PermissionRequest注解的方法内插入权限请求的代码,根据PermissionRequest.needReCall来决定是否需要在权限回调成功的方法里插入代码
175 | for (CtMethod method : c.getDeclaredMethods()) {
176 | PermissionRequest permissionRequest = method.getAnnotation(PermissionRequest.class)
177 | //没有注解的方法忽略
178 | if (null == permissionRequest) {
179 | continue
180 | }
181 | project.logger.error "SimplePermission-----> method returnType : " + method.getReturnType().name
182 | //带返回值的方法暂时忽略
183 | if (!method.getReturnType().name.contains("void")) {
184 | continue
185 | }
186 | //静态方法忽略
187 | if (Modifier.isStatic(method.getModifiers())) {
188 | continue
189 | }
190 | project.logger.error "SimplePermission-----> find requestPermission method : " + method.longName
191 | //因为javassist不支持"{"与"}"有多行数据生成数组,所以要用一个String[] xx=new String[n]形式的数组把权限存储下来
192 | StringBuilder requestMethodBuilder = new StringBuilder()
193 | .append("String []requestPermissions = new String[")
194 | .append(permissionRequest.requestPermissions().length)
195 | .append("];\n")
196 | int eachIndex = 0
197 | for (String permission : permissionRequest.requestPermissions()) {
198 | requestMethodBuilder.append("requestPermissions[")
199 | .append(eachIndex)
200 | .append("] = \"")
201 | .append(permission)
202 | .append("\";\n")
203 | eachIndex++
204 | }
205 |
206 | //因为前面已经排除了非Activity和Fragment的class
207 | boolean isActivity = c.subclassOf(pool.get(ACTIVITY_PATH))
208 | requestMethodBuilder.append("final boolean hasPermissions = PermissionsManager.getInstance().hasAllPermissions(")
209 | // $0代码的是this,$1代表方法参数的第一个参数、$2代表方法参数的第二个参数,以此类推,$N代表是方法参数的第N个。
210 | .append("\$0")
211 | if (!isActivity) {
212 | requestMethodBuilder.append(".getActivity()")
213 | }
214 | requestMethodBuilder.append(",")
215 | .append("requestPermissions );\n")
216 | .append("if (!hasPermissions) {\n")
217 | //如果需要在权限申请成功后继续执行此方法的逻辑代码,则需要存储参数
218 | if (permissionRequest.needReCall()) {
219 | //开始存储方法参数
220 | CtClass[] mParameterTypes = method.getParameterTypes()
221 | //权限申请成功的方法插入代码
222 | CtMethod onSuccessMethod = c.getDeclaredMethod("onSuccess", CtClass.intType)
223 | if (null != onSuccessMethod) {
224 | StringBuilder onSuccessMethodBuilder = new StringBuilder("List params = requestPermissionMethodParams.get(Integer.valueOf(\$1));\n")
225 | .append("if(\$1==")
226 | .append(permissionRequest.requestCode())
227 | .append("){\n")
228 | .append(method.getName())
229 | .append("(")
230 | if (null != mParameterTypes && mParameterTypes.length > 0) {
231 | for (int k = 0; k < mParameterTypes.length; k++) {
232 | onSuccessMethodBuilder.append("(")
233 | .append(mParameterTypes[0].name)
234 | .append(")")
235 | .append("params.get(")
236 | .append(k)
237 | .append(")")
238 | if (k != mParameterTypes.length - 1) {
239 | onSuccessMethodBuilder.append(",")
240 | }
241 | }
242 | }
243 | onSuccessMethodBuilder.append()
244 | .append(");\n")
245 | .append("return;\n")
246 | .append("}\n")
247 |
248 | project.logger.error "SimplePermission-----> onSuccess method insert content :\n " + onSuccessMethodBuilder.toString()
249 | onSuccessMethod.insertBefore(onSuccessMethodBuilder.toString())
250 | }
251 | //在申请权限的方法内部插入存储参数的代码
252 | if (null != mParameterTypes && mParameterTypes.length > 0) {
253 | requestMethodBuilder.append("List params = new java.util.ArrayList();\n")
254 | for (int k = 0; k < mParameterTypes.length; k++) {
255 | requestMethodBuilder.append("params.add(\$")
256 | .append(k + 1)
257 | .append(");\n")
258 | }
259 | requestMethodBuilder.append("requestPermissionMethodParams.put(")
260 | .append("Integer.valueOf(")
261 | .append(permissionRequest.requestCode())
262 | .append(")")
263 | .append(",")
264 | .append("params);\n")
265 | }
266 | }
267 | requestMethodBuilder.append("PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(")
268 | .append(permissionRequest.requestCode())//requestCode
269 | .append(",")
270 | .append("\$0,")
271 | .append("requestPermissions,")
272 | .append("\$0);\n")
273 | //申请权限的方法的代码逻辑需要等到权限申请成功后才能执行的话,这里要在申请权限的代码后加上return,所以这个库目前有一个限制:带返回参数的方法暂不支持
274 | if (permissionRequest.needReCall()) {
275 | requestMethodBuilder.append("return;\n")
276 | }
277 | requestMethodBuilder.append("}\n")
278 | project.logger.error "SimplePermission-----> requestPermission method insert content :\n " + requestMethodBuilder.toString()
279 | method.insertBefore(requestMethodBuilder.toString())
280 | }
281 |
282 | c.writeFile(path)
283 | c.detach()
284 | } catch (Exception e) {
285 | c.detach()
286 | e.printStackTrace()
287 | throw new RuntimeException(e)
288 | }
289 | }
290 | }
291 |
292 | static CtMethod findMethodByName(CtClass ctClass, String methodName) {
293 | //getDeclaredMethods获取自己申明的方法,c.getMethods()会把所有父类的方法都加上
294 | for (CtMethod method : ctClass.getDeclaredMethods()) {
295 | if (method.getLongName().contains(methodName)) {
296 | return method
297 | }
298 | }
299 | return null
300 | }
301 |
302 | static CtField findFieldByName(CtClass ctClass, String fieldName) {
303 | for (CtField field : ctClass.getDeclaredFields()) {
304 | if (field.getName().equals(fieldName)) {
305 | return field
306 | }
307 | }
308 | return null
309 | }
310 | }
--------------------------------------------------------------------------------
/permissionplugin/src/main/groovy/com/ykbjson/lib/plugin/SimplePermissionTransform.groovy:
--------------------------------------------------------------------------------
1 | package com.ykbjson.lib.plugin
2 |
3 | import com.android.build.api.transform.*
4 | import com.android.build.gradle.internal.pipeline.TransformManager
5 | import org.apache.commons.codec.digest.DigestUtils
6 | import org.apache.commons.io.FileUtils
7 | import org.gradle.api.Project
8 |
9 | public class SimplePermissionTransform extends Transform {
10 |
11 |
12 | private Project mProject;
13 |
14 | SimplePermissionTransform(Project mProject) {
15 | this.mProject = mProject
16 | }
17 |
18 | // 设置我们自定义的Transform对应的Task名称
19 | // 类似:TransformClassesWithPreDexForXXX
20 | @Override
21 | String getName() {
22 | return "SimplePermissionTransform"
23 | }
24 |
25 | // 指定输入的类型,通过这里的设定,可以指定我们要处理的文件类型
26 | //这样确保其他类型的文件不会传入
27 | @Override
28 | Set getInputTypes() {
29 | return TransformManager.CONTENT_CLASS
30 | }
31 |
32 | // 指Transform要操作内容的范围,官方文档Scope有7种类型:
33 | //
34 | // EXTERNAL_LIBRARIES 只有外部库
35 | // PROJECT 只有项目内容
36 | // PROJECT_LOCAL_DEPS 只有项目的本地依赖(本地jar)
37 | // PROVIDED_ONLY 只提供本地或远程依赖项
38 | // SUB_PROJECTS 只有子项目。
39 | // SUB_PROJECTS_LOCAL_DEPS 只有子项目的本地依赖项(本地jar)。
40 | // TESTED_CODE 由当前变量(包括依赖项)测试的代码
41 | @Override
42 | Set getScopes() {
43 | return TransformManager.SCOPE_FULL_PROJECT
44 | }
45 |
46 | @Override
47 | boolean isIncremental() {
48 | return false
49 | }
50 |
51 | /**
52 | * 具体的处理
53 | */
54 | @Override
55 | void transform(Context context, Collection inputs,
56 | Collection referencedInputs,
57 | TransformOutputProvider outputProvider, boolean isIncremental)
58 | throws IOException, TransformException, InterruptedException {
59 | mProject.logger.error "==============SimplePermission transform start=============="
60 | try {
61 | // Transform的inputs有两种类型,一种是目录,一种是jar包,要分开遍历
62 | inputs.each { TransformInput input ->
63 | //对类型为“文件夹”的input进行遍历
64 | input.directoryInputs.each { DirectoryInput directoryInput ->
65 | //文件夹里面包含的是我们手写的类以及R.class、BuildConfig.class以及R$XXX.class等
66 | // String packageName=project.extensions.findByName("applicationId")
67 | SimplePermissionPluginInject.injectDir(mProject, directoryInput.file.absolutePath, "com/ykbjson/app/simplepermission")
68 | // 获取output目录
69 | def dest = outputProvider.getContentLocation(directoryInput.name,
70 | directoryInput.contentTypes, directoryInput.scopes,
71 | Format.DIRECTORY)
72 |
73 | // 将input的目录复制到output指定目录
74 | FileUtils.copyDirectory(directoryInput.file, dest)
75 | }
76 | //对类型为jar文件的input进行遍历
77 | input.jarInputs.each { JarInput jarInput ->
78 | //jar文件一般是第三方依赖库jar文件
79 | SimplePermissionPluginInject.injectJar(mProject, jarInput.file.absolutePath, "com/ykbjson/app/simplepermission")
80 | // 重命名输出文件(同目录copyFile会冲突)
81 | def jarName = jarInput.name
82 | def md5Name = DigestUtils.md5Hex(jarInput.file.getAbsolutePath())
83 | if (jarName.endsWith(".jar")) {
84 | jarName = jarName.substring(0, jarName.length() - 4)
85 | }
86 | //生成输出路径
87 | def dest = outputProvider.getContentLocation(jarName + md5Name,
88 | jarInput.contentTypes, jarInput.scopes, Format.JAR)
89 | //将输入内容复制到输出
90 | FileUtils.copyFile(jarInput.file, dest)
91 | }
92 | }
93 |
94 | } catch (Exception e) {
95 | SimplePermissionPluginInject.removeClassPath(mProject)
96 | throw new RuntimeException(e)
97 | }
98 | SimplePermissionPluginInject.removeClassPath(mProject)
99 | mProject.logger.error "==============SimplePermission transform end=============="
100 | }
101 | }
--------------------------------------------------------------------------------
/permissionplugin/src/main/resources/META-INF/gradle-plugins/com.ykbjson.simplepermission.properties:
--------------------------------------------------------------------------------
1 | implementation-class=com.ykbjson.lib.plugin.SimplePermissionPlugin
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':simplepermission', ':permissionplugin', ':simplepermission_ano'
2 |
--------------------------------------------------------------------------------
/simplepermission/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/simplepermission/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'com.novoda.bintray-release'
3 | apply plugin: 'maven'
4 | apply plugin: 'com.github.dcendents.android-maven'
5 |
6 |
7 | //加载资源
8 | Properties properties = new Properties()
9 | InputStream inputStream = project.rootProject.file('local.properties').newDataInputStream();
10 | properties.load(inputStream)
11 |
12 | publish {
13 | bintrayUser = properties.getProperty("bintrayUser")
14 | bintrayKey = properties.getProperty("bintrayKey")
15 | userOrg = 'ykbjson' // bintray注册的用户名
16 | groupId = rootProject.ext.bintray.group
17 | artifactId = 'simplepermission'// bintray创建的package
18 | publishVersion = rootProject.ext.bintray.libraryVersion
19 | desc = 'SimplePermission权限申请库核心代码'
20 | }
21 |
22 | //group和version
23 | group='com.github.ykbjson'
24 | //version=rootProject.ext.bintray.plugVersion
25 |
26 | android {
27 | compileSdkVersion rootProject.ext.android.compileSdkVersion
28 |
29 | defaultConfig {
30 | minSdkVersion rootProject.ext.android.minSdkVersion
31 | targetSdkVersion rootProject.ext.android.targetSdkVersion
32 | versionCode rootProject.ext.android.versionCode
33 | versionName rootProject.ext.android.versionName
34 | }
35 | lintOptions {
36 | abortOnError false
37 | }
38 | }
39 |
40 | dependencies {
41 | implementation fileTree(dir: 'libs', include: ['*.jar'])
42 | implementation rootProject.ext.dependencies.appCompat
43 | implementation rootProject.ext.dependencies.RXAndroid
44 | implementation rootProject.ext.dependencies.RXJava
45 | }
46 |
--------------------------------------------------------------------------------
/simplepermission/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/simplepermission/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/simplepermission/src/main/java/com/ykbjson/lib/simplepermission/Permissions.java:
--------------------------------------------------------------------------------
1 | package com.ykbjson.lib.simplepermission;
2 |
3 | /**
4 | * Desription:Enum class to handle the different states
5 | * of permissions since the PackageManager only
6 | * has a granted and denied state.
7 | * Creator:yankebin
8 | * CreatedAt:2018/11/7
9 | */
10 | enum Permissions {
11 | GRANTED,
12 | DENIED,
13 | NOT_FOUND,
14 | USER_DENIED_FOREVER
15 | }
--------------------------------------------------------------------------------
/simplepermission/src/main/java/com/ykbjson/lib/simplepermission/PermissionsManager.java:
--------------------------------------------------------------------------------
1 | package com.ykbjson.lib.simplepermission;
2 |
3 | import android.Manifest;
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import android.content.pm.PackageInfo;
7 | import android.content.pm.PackageManager;
8 | import android.os.Build;
9 | import android.support.annotation.NonNull;
10 | import android.support.annotation.Nullable;
11 | import android.support.v4.app.ActivityCompat;
12 | import android.support.v4.app.Fragment;
13 | import android.support.v4.content.PermissionChecker;
14 | import android.util.Log;
15 |
16 | import java.lang.reflect.Field;
17 | import java.util.ArrayList;
18 | import java.util.HashSet;
19 | import java.util.Iterator;
20 | import java.util.List;
21 | import java.util.Set;
22 |
23 | /**
24 | * Desription:A class to help you manage your permissions simply.
25 | * Creator:yankebin
26 | * CreatedAt:2018/11/7
27 | */
28 | public class PermissionsManager {
29 | private final String TAG = getClass().getName();
30 | private final Set mPendingRequests = new HashSet<>(1);
31 | private final Set mPermissions = new HashSet<>(1);
32 | private final List mPendingActions = new ArrayList<>(1);
33 |
34 | private boolean enableLog;
35 | private static volatile PermissionsManager mInstance = null;
36 |
37 | public static PermissionsManager getInstance() {
38 | if (null == mInstance) {
39 | synchronized (PermissionsManager.class) {
40 | if (mInstance == null) {
41 | mInstance = new PermissionsManager();
42 | }
43 | }
44 | }
45 | return mInstance;
46 | }
47 |
48 | private PermissionsManager() {
49 | initializePermissionsMap();
50 | }
51 |
52 | /**
53 | * This method uses reflection to read all the permissions in the Manifest class.
54 | * This is necessary because some permissions do not exist on older versions of Android,
55 | * since they do not exist, they will be denied when you check whether you have permission
56 | * which is problematic since a new permission is often added where there was no previous
57 | * permission required. We initialize a Set of available permissions and check the set
58 | * when checking if we have permission since we want to know when we are denied a permission
59 | * because it doesn't exist yet.
60 | */
61 | private synchronized void initializePermissionsMap() {
62 | Field[] fields = Manifest.permission.class.getFields();
63 | for (Field field : fields) {
64 | String name = null;
65 | try {
66 | name = (String) field.get("");
67 | } catch (IllegalAccessException e) {
68 | if (enableLog) {
69 | Log.d(TAG, "Could not access field", e);
70 | }
71 | }
72 | mPermissions.add(name);
73 | }
74 | }
75 |
76 | /**
77 | * This method retrieves all the permissions declared in the application's manifest.
78 | * It returns a non null array of permisions that can be declared.
79 | *
80 | * @param activity the Activity necessary to check what permissions we have.
81 | * @return a non null array of permissions that are declared in the application manifest.
82 | */
83 | @NonNull
84 | public synchronized String[] getManifestPermissions(@NonNull final Activity activity) {
85 | PackageInfo packageInfo = null;
86 | List list = new ArrayList<>(1);
87 | try {
88 | if (enableLog) {
89 | Log.d(TAG, activity.getPackageName());
90 | }
91 | packageInfo = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_PERMISSIONS);
92 | } catch (PackageManager.NameNotFoundException e) {
93 | if (enableLog) {
94 | Log.d(TAG, "A problem occurred when retrieving permissions", e);
95 | }
96 | }
97 | if (packageInfo != null) {
98 | String[] permissions = packageInfo.requestedPermissions;
99 | if (permissions != null) {
100 | for (String perm : permissions) {
101 | if (enableLog) {
102 | Log.d(TAG, "Manifest contained permission: " + perm);
103 | }
104 | list.add(perm);
105 |
106 | }
107 | }
108 | }
109 | return list.toArray(new String[list.size()]);
110 | }
111 |
112 | /**
113 | * This method adds the {@link PermissionsResultAction} to the current list
114 | * of pending actions that will be completed when the permissions are
115 | * received. The list of permissions passed to this method are registered
116 | * in the PermissionsResultAction object so that it will be notified of changes
117 | * made to these permissions.
118 | *
119 | * @param permissions the required permissions for the action to be executed.
120 | * @param action the action to add to the current list of pending actions.
121 | */
122 | private synchronized void addPendingAction(@NonNull String[] permissions,
123 | @Nullable PermissionsResultAction action) {
124 | if (action == null) {
125 | return;
126 | }
127 | action.registerPermissions(permissions);
128 | mPendingActions.add(action);
129 | }
130 |
131 | /**
132 | * This method removes a pending action from the list of pending actions.
133 | * It is used for cases where the permission has already been granted, so
134 | * you immediately wish to remove the pending action from the queue and
135 | * execute the action.
136 | *
137 | * @param action the action to remove
138 | */
139 | private synchronized void removePendingAction(@Nullable PermissionsResultAction action) {
140 | for (Iterator iterator = mPendingActions.iterator();
141 | iterator.hasNext(); ) {
142 | PermissionsResultAction weakRef = iterator.next();
143 | if (weakRef == action || weakRef == null) {
144 | iterator.remove();
145 | }
146 | }
147 | }
148 |
149 | /**
150 | * This static method can be used to check whether or not you have a specific permission.
151 | * It is basically a less verbose method of using {@link ActivityCompat#checkSelfPermission(Context, String)}
152 | * and will simply return a boolean whether or not you have the permission. If you pass
153 | * in a null Context object, it will return false as otherwise it cannot check the permission.
154 | * However, the Activity parameter is nullable so that you can pass in a reference that you
155 | * are not always sure will be valid or not (e.g. getActivity() from Fragment).
156 | *
157 | * @param context the Context necessary to check the permission
158 | * @param permission the permission to check
159 | * @return true if you have been granted the permission, false otherwise
160 | */
161 | public synchronized boolean hasPermission(@Nullable Context context, @NonNull String permission) {
162 | return context != null && (PermissionChecker.checkSelfPermission(context, permission)
163 | == PackageManager.PERMISSION_GRANTED || !mPermissions.contains(permission));
164 | }
165 |
166 | /**
167 | * This static method can be used to check whether or not you have several specific permissions.
168 | * It is simpler than checking using {@link ActivityCompat#checkSelfPermission(Context, String)}
169 | * for each permission and will simply return a boolean whether or not you have all the permissions.
170 | * If you pass in a null Context object, it will return false as otherwise it cannot check the
171 | * permission. However, the Activity parameter is nullable so that you can pass in a reference
172 | * that you are not always sure will be valid or not (e.g. getActivity() from Fragment).
173 | *
174 | * @param context the Context necessary to check the permission
175 | * @param permissions the permissions to check
176 | * @return true if you have been granted all the permissions, false otherwise
177 | */
178 | public synchronized boolean hasAllPermissions(@Nullable Context context, @NonNull String[] permissions) {
179 | if (context == null) {
180 | return false;
181 | }
182 | boolean hasAllPermissions = true;
183 | for (String perm : permissions) {
184 | hasAllPermissions &= hasPermission(context, perm);
185 | }
186 | return hasAllPermissions;
187 | }
188 |
189 | /**
190 | * This static method can be used to check whether or not you have several specific permissions.
191 | * It is simpler than checking using {@link ActivityCompat#checkSelfPermission(Context, String)}
192 | * for each permission and will simply return a boolean whether or not you have all the permissions.
193 | * If you pass in a null Context object, it will return false as otherwise it cannot check the
194 | * permission. However, the Activity parameter is nullable so that you can pass in a reference
195 | * that you are not always sure will be valid or not (e.g. getActivity() from Fragment).
196 | *
197 | * @param context the Context necessary to check the permission
198 | * @return true if you have been granted all the permissions, false otherwise
199 | */
200 | public synchronized boolean hasAllPermissions(@Nullable Activity context) {
201 | if (context == null) {
202 | return false;
203 | }
204 | String[] perms = getManifestPermissions(context);
205 | return hasAllPermissions(context, perms);
206 | }
207 |
208 | /**
209 | * This method will request all the permissions declared in your application manifest
210 | * for the specified {@link PermissionsResultAction}. The purpose of this method is to enable
211 | * all permissions to be requested at one shot. The PermissionsResultAction is used to notify
212 | * you of the user allowing or denying each permission. The Activity and PermissionsResultAction
213 | * parameters are both annotated Nullable, but this method will not work if the Activity
214 | * is null. It is only annotated Nullable as a courtesy to prevent crashes in the case
215 | * that you call this from a Fragment where {@link Fragment#getActivity()} could yield
216 | * null. Additionally, you will not receive any notification of permissions being granted
217 | * if you provide a null PermissionsResultAction.
218 | *
219 | * @param requestCode the permissions requestCode
220 | * @param activity the Activity necessary to request and check permissions.
221 | * @param callback the PermissionsRequestCallback used to notify you of permissions being accepted.
222 | */
223 | public synchronized void requestAllManifestPermissionsIfNecessary(int requestCode, @Nullable Activity activity,
224 | @Nullable PermissionsRequestCallback callback) {
225 | if (activity == null) {
226 | return;
227 | }
228 | String[] perms = getManifestPermissions(activity);
229 | requestPermissionsIfNecessaryForResult(requestCode, activity, perms, callback);
230 | }
231 |
232 | /**
233 | * This method should be used to execute a {@link PermissionsResultAction} for the array
234 | * of permissions passed to this method. This method will request the permissions if
235 | * they need to be requested (i.e. we don't have permission yet) and will add the
236 | * PermissionsResultAction to the queue to be notified of permissions being granted or
237 | * denied. In the case of pre-Android Marshmallow, permissions will be granted immediately.
238 | * The Activity variable is nullable, but if it is null, the method will fail to execute.
239 | * This is only nullable as a courtesy for Fragments where getActivity() may yeild null
240 | * if the Fragment is not currently added to its parent Activity.
241 | *
242 | * @param requestCode the permissions requestCode
243 | * @param activity the activity necessary to request the permissions.
244 | * @param permissions the list of permissions to request for the {@link PermissionsResultAction}.
245 | * @param callback the PermissionsRequestCallback to notify when the permissions are granted or denied.
246 | */
247 | public synchronized void requestPermissionsIfNecessaryForResult(int requestCode, @Nullable Activity activity,
248 | @NonNull String[] permissions,
249 | @Nullable PermissionsRequestCallback callback) {
250 | if (activity == null) {
251 | return;
252 | }
253 | final PermissionsResultAction action = new PermissionsResultAction(requestCode, callback);
254 | addPendingAction(permissions, action);
255 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
256 | doPermissionWorkBeforeAndroidM(activity, permissions, action);
257 | } else {
258 | List permList = getPermissionsListToRequest(activity, permissions, action);
259 | if (permList.isEmpty()) {
260 | //if there is no permission to request, there is no reason to keep the action in the list
261 | removePendingAction(action);
262 | } else {
263 | String[] permsToRequest = permList.toArray(new String[permList.size()]);
264 | mPendingRequests.addAll(permList);
265 | ActivityCompat.requestPermissions(activity, permsToRequest, 1);
266 | }
267 | }
268 | }
269 |
270 | /**
271 | * This method should be used to execute a {@link PermissionsResultAction} for the array
272 | * of permissions passed to this method. This method will request the permissions if
273 | * they need to be requested (i.e. we don't have permission yet) and will add the
274 | * PermissionsResultAction to the queue to be notified of permissions being granted or
275 | * denied. In the case of pre-Android Marshmallow, permissions will be granted immediately.
276 | * The Fragment variable is used, but if {@link Fragment#getActivity()} returns null, this method
277 | * will fail to work as the activity reference is necessary to check for permissions.
278 | *
279 | * @param requestCode the permissions requestCode
280 | * @param fragment the fragment necessary to request the permissions.
281 | * @param permissions the list of permissions to request for the {@link PermissionsResultAction}.
282 | * @param callback the PermissionsRequestCallback to notify when the permissions are granted or denied.
283 | */
284 | public synchronized void requestPermissionsIfNecessaryForResult(int requestCode, @NonNull Fragment fragment,
285 | @NonNull String[] permissions,
286 | @Nullable PermissionsRequestCallback callback) {
287 | Activity activity = fragment.getActivity();
288 | if (activity == null) {
289 | return;
290 | }
291 | final PermissionsResultAction action = new PermissionsResultAction(requestCode, callback);
292 | addPendingAction(permissions, action);
293 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
294 | doPermissionWorkBeforeAndroidM(activity, permissions, action);
295 | } else {
296 | List permList = getPermissionsListToRequest(activity, permissions, action);
297 | if (permList.isEmpty()) {
298 | //if there is no permission to request, there is no reason to keep the action int the list
299 | removePendingAction(action);
300 | } else {
301 | String[] permsToRequest = permList.toArray(new String[permList.size()]);
302 | mPendingRequests.addAll(permList);
303 | fragment.requestPermissions(permsToRequest, 1);
304 | }
305 | }
306 | }
307 |
308 |
309 | /**
310 | * This method should be used to execute a {@link PermissionsResultAction} for the array
311 | * of permissions passed to this method. This method will request the permissions if
312 | * they need to be requested (i.e. we don't have permission yet) and will add the
313 | * PermissionsResultAction to the queue to be notified of permissions being granted or
314 | * denied. In the case of pre-Android Marshmallow, permissions will be granted immediately.
315 | * The Fragment variable is used, but if {@link android.app.Fragment#getActivity()} returns null, this method
316 | * will fail to work as the activity reference is necessary to check for permissions.
317 | *
318 | * @param requestCode the permissions requestCode
319 | * @param fragment the android.app.fragment necessary to request the permissions.
320 | * @param permissions the list of permissions to request for the {@link PermissionsResultAction}.
321 | * @param callback the PermissionsRequestCallback to notify when the permissions are granted or denied.
322 | */
323 | public synchronized void requestPermissionsIfNecessaryForResult(int requestCode, @NonNull android.app.Fragment fragment,
324 | @NonNull String[] permissions,
325 | @Nullable PermissionsRequestCallback callback) {
326 | Activity activity = fragment.getActivity();
327 | if (activity == null) {
328 | return;
329 | }
330 | final PermissionsResultAction action = new PermissionsResultAction(requestCode, callback);
331 | addPendingAction(permissions, action);
332 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
333 | doPermissionWorkBeforeAndroidM(activity, permissions, action);
334 | } else {
335 | List permList = getPermissionsListToRequest(activity, permissions, action);
336 | if (permList.isEmpty()) {
337 | //if there is no permission to request, there is no reason to keep the action int the list
338 | removePendingAction(action);
339 | } else {
340 | String[] permsToRequest = permList.toArray(new String[permList.size()]);
341 | mPendingRequests.addAll(permList);
342 | fragment.requestPermissions(permsToRequest, 1);
343 | }
344 | }
345 | }
346 |
347 | /**
348 | * This method notifies the PermissionsManager that the permissions have change. If you are making
349 | * the permissions requests using an Activity, then this method should be called from the
350 | * Activity callback onRequestPermissionsResult() with the variables passed to that method. If
351 | * you are passing a Fragment to make the permissions request, then you should call this in
352 | * the {@link Fragment#onRequestPermissionsResult(int, String[], int[])} method.
353 | * It will notify all the pending PermissionsResultAction objects currently
354 | * in the queue, and will remove the permissions request from the list of pending requests.
355 | *
356 | * @param permissions the permissions that have changed.
357 | * @param results the values for each permission.
358 | */
359 | public synchronized void notifyPermissionsChange(@NonNull String[] permissions, @NonNull int[] results) {
360 | int size = permissions.length;
361 | if (results.length < size) {
362 | size = results.length;
363 | }
364 | Iterator iterator = mPendingActions.iterator();
365 | while (iterator.hasNext()) {
366 | PermissionsResultAction action = iterator.next();
367 | for (int n = 0; n < size; n++) {
368 | if (action == null || action.onResult(permissions[n], results[n])) {
369 | iterator.remove();
370 | break;
371 | }
372 | }
373 | }
374 | for (int n = 0; n < size; n++) {
375 | mPendingRequests.remove(permissions[n]);
376 | }
377 | }
378 |
379 | /**
380 | * When request permissions on devices before Android M (Android 6.0, API Level 23)
381 | * Do the granted or denied work directly according to the permission status
382 | *
383 | * @param activity the activity to check permissions
384 | * @param permissions the permissions names
385 | * @param action the callback work object, containing what we what to do after
386 | * permission check
387 | */
388 | private void doPermissionWorkBeforeAndroidM(@NonNull Activity activity,
389 | @NonNull String[] permissions,
390 | @Nullable PermissionsResultAction action) {
391 | for (String perm : permissions) {
392 | if (action != null) {
393 | if (!mPermissions.contains(perm)) {
394 | action.onResult(perm, Permissions.NOT_FOUND);
395 | } else if (ActivityCompat.checkSelfPermission(activity, perm)
396 | != PackageManager.PERMISSION_GRANTED) {
397 | action.onResult(perm, Permissions.DENIED);
398 | } else {
399 | action.onResult(perm, Permissions.GRANTED);
400 | }
401 | }
402 | }
403 | }
404 |
405 | /**
406 | * Filter the permissions list:
407 | * If a permission is not granted, add it to the result list
408 | * if a permission is granted, do the granted work, do not add it to the result list
409 | *
410 | * @param activity the activity to check permissions
411 | * @param permissions all the permissions names
412 | * @param action the callback work object, containing what we what to do after
413 | * permission check
414 | * @return a list of permissions names that are not granted yet
415 | */
416 | @NonNull
417 | private List getPermissionsListToRequest(@NonNull Activity activity,
418 | @NonNull String[] permissions,
419 | @Nullable PermissionsResultAction action) {
420 | List permList = new ArrayList<>(permissions.length);
421 | for (String perm : permissions) {
422 | if (!mPermissions.contains(perm)) {
423 | if (action != null) {
424 | action.onResult(perm, Permissions.NOT_FOUND);
425 | }
426 | } else if (PermissionChecker.checkSelfPermission(activity, perm) != PackageManager.PERMISSION_GRANTED) {
427 | if (ActivityCompat.shouldShowRequestPermissionRationale(activity, perm)) {
428 | if (action != null) {
429 | action.onResult(perm, Permissions.USER_DENIED_FOREVER);
430 | }
431 | } else if (!mPendingRequests.contains(perm)) {
432 | permList.add(perm);
433 | }
434 | } else {
435 | if (action != null) {
436 | action.onResult(perm, Permissions.GRANTED);
437 | }
438 | }
439 | }
440 | return permList;
441 | }
442 |
443 | /**
444 | * Set Log status
445 | *
446 | * @param enableLog Log status value
447 | */
448 | public void setEnableLog(boolean enableLog) {
449 | this.enableLog = enableLog;
450 | }
451 |
452 | /**
453 | * return Log status
454 | *
455 | * @return Log status
456 | */
457 | public boolean isEnableLog() {
458 | return enableLog;
459 | }
460 | }
--------------------------------------------------------------------------------
/simplepermission/src/main/java/com/ykbjson/lib/simplepermission/PermissionsRequestCallback.java:
--------------------------------------------------------------------------------
1 | package com.ykbjson.lib.simplepermission;
2 |
3 | /**
4 | * Description:权限申请结果回调
5 | * Creator:yankebin
6 | * CreatedAt:2018/11/1
7 | */
8 | public interface PermissionsRequestCallback {
9 | /**
10 | * This method is called when a permission that have been
11 | * requested have been granted by the user. In this method
12 | * you should put your permission(s) sensitive code that can
13 | * only be executed with the required permissions.
14 | */
15 | void onGranted(int requestCode, String permission);
16 |
17 | /**
18 | * This method is called when a permission has been denied by
19 | * the user. It provides you with the permission that was denied
20 | * and will be executed on the Looper you pass to the constructor
21 | * of this class, or the Looper that this object was created on.
22 | *
23 | * @param permission the permission that was denied.
24 | */
25 | void onDenied(int requestCode, String permission);
26 |
27 | /**
28 | * This method is called when a permission has been denied by
29 | * the user forever. It provides you with the permission that was denied
30 | * and will be executed on the Looper you pass to the constructor
31 | * of this class, or the Looper that this object was created on.
32 | *
33 | * @param permission the permission that was denied.
34 | */
35 | void onDeniedForever(int requestCode, String permission);
36 |
37 | /**
38 | * This method is called when all permissions has been check complete
39 | * but some permissions denied.
40 | *
41 | * @param deniedPermissions those denied permissions
42 | */
43 | void onFailure(int requestCode, String[] deniedPermissions);
44 |
45 | /**
46 | * This method is called when all permissions has been check complete
47 | * and all permissions granted.
48 | */
49 | void onSuccess(int requestCode);
50 | }
51 |
--------------------------------------------------------------------------------
/simplepermission/src/main/java/com/ykbjson/lib/simplepermission/PermissionsResultAction.java:
--------------------------------------------------------------------------------
1 |
2 | package com.ykbjson.lib.simplepermission;
3 |
4 | import android.content.pm.PackageManager;
5 | import android.os.Looper;
6 | import android.support.annotation.CallSuper;
7 | import android.support.annotation.NonNull;
8 | import android.support.annotation.Nullable;
9 | import android.util.Log;
10 |
11 | import java.util.Collections;
12 | import java.util.HashSet;
13 | import java.util.Set;
14 |
15 | import io.reactivex.Scheduler;
16 | import io.reactivex.android.schedulers.AndroidSchedulers;
17 |
18 | /**
19 | * Desription:This abstract class should be used to create an if/else action that the PermissionsManager
20 | * can execute when the permissions you request are granted or denied. Simple use involves
21 | * creating an anonymous instance of it and passing that instance to the
22 | * requestPermissionsIfNecessaryForResult method. The result will be sent back to you as
23 | * either onGranted (all permissions have been granted), or onDenied (a required permission
24 | * has been denied). Ideally you put your functionality in the onGranted method and notify
25 | * the user what won't work in the onDenied method.
26 | * Creator:yankebin
27 | * CreatedAt:2018/11/7
28 | */
29 | public class PermissionsResultAction {
30 | private final String TAG = getClass().getName();
31 |
32 | private Looper mLooper = Looper.getMainLooper();
33 | private final Set mPermissions = new HashSet<>(1);
34 | private final Set mDeniedPermissions = new HashSet<>(1);
35 |
36 | private final PermissionsRequestCallback mPermissionsRequestCallback;
37 | private final int mRequestCode;
38 |
39 | /**
40 | * Default Constructor
41 | */
42 | public PermissionsResultAction(int requestCode, @Nullable PermissionsRequestCallback permissionsRequestCallback) {
43 | mRequestCode = requestCode;
44 | mPermissionsRequestCallback = permissionsRequestCallback;
45 | }
46 |
47 | /**
48 | * Alternate Constructor. Pass the looper you wish the PermissionsResultAction
49 | * callbacks to be executed on if it is not the current Looper. For instance,
50 | * if you are making a permissions request from a background thread but wish the
51 | * callback to be on the UI thread, use this constructor to specify the UI Looper.
52 | *
53 | * @param looper the looper that the callbacks will be called using.
54 | */
55 | public PermissionsResultAction(int requestCode, @Nullable PermissionsRequestCallback permissionsRequestCallback, @NonNull Looper looper) {
56 | this(requestCode, permissionsRequestCallback);
57 | mLooper = looper;
58 | }
59 |
60 | /**
61 | * This method is called when a permission that have been
62 | * requested have been granted by the user. In this method
63 | * you should put your permission(s) sensitive code that can
64 | * only be executed with the required permissions.
65 | */
66 | public void onGranted(String permission) {
67 | if (null != mPermissionsRequestCallback) {
68 | mPermissionsRequestCallback.onGranted(mRequestCode, permission);
69 | }
70 | }
71 |
72 | /**
73 | * This method is called when a permission has been denied by
74 | * the user. It provides you with the permission that was denied
75 | * and will be executed on the Looper you pass to the constructor
76 | * of this class, or the Looper that this object was created on.
77 | *
78 | * @param permission the permission that was denied.
79 | */
80 | public void onDenied(String permission) {
81 | if (null != mPermissionsRequestCallback) {
82 | mPermissionsRequestCallback.onDenied(mRequestCode, permission);
83 | }
84 | }
85 |
86 | /**
87 | * This method is called when a permission has been denied by
88 | * the user forever. It provides you with the permission that was denied
89 | * and will be executed on the Looper you pass to the constructor
90 | * of this class, or the Looper that this object was created on.
91 | *
92 | * @param permission the permission that was denied.
93 | */
94 | public void onDeniedForever(String permission) {
95 | if (null != mPermissionsRequestCallback) {
96 | mPermissionsRequestCallback.onDeniedForever(mRequestCode, permission);
97 | }
98 | }
99 |
100 | /**
101 | * This method is called when all permissions has been check complete
102 | * but some permissions denied.
103 | *
104 | * @param deniedPermissions those denied permissions
105 | */
106 | public void onFailure(String[] deniedPermissions) {
107 | if (null != mPermissionsRequestCallback) {
108 | mPermissionsRequestCallback.onFailure(mRequestCode, deniedPermissions);
109 | }
110 | }
111 |
112 | /**
113 | * This method is called when all permissions has been check complete
114 | * and all permissions granted.
115 | */
116 | public void onSuccess() {
117 | if (null != mPermissionsRequestCallback) {
118 | mPermissionsRequestCallback.onSuccess(mRequestCode);
119 | }
120 | }
121 |
122 | /**
123 | * This method is used to determine if a permission not
124 | * being present on the current Android platform should
125 | * affect whether the PermissionsResultAction should continue
126 | * listening for events. By default, it returns true and will
127 | * simply ignore the permission that did not exist. Usually this will
128 | * work fine since most new permissions are introduced to
129 | * restrict what was previously allowed without permission.
130 | * If that is not the case for your particular permission you
131 | * request, override this method and return false to result in the
132 | * Action being denied.
133 | *
134 | * @param permission the permission that doesn't exist on this
135 | * Android version
136 | * @return return true if the PermissionsResultAction should
137 | * ignore the lack of the permission and proceed with exection
138 | * or false if the PermissionsResultAction should treat the
139 | * absence of the permission on the API level as a denial.
140 | */
141 | public synchronized boolean shouldIgnorePermissionNotFound(String permission) {
142 | if (PermissionsManager.getInstance().isEnableLog()) {
143 | Log.d(TAG, "Permission not found: " + permission);
144 | }
145 | return true;
146 | }
147 |
148 |
149 | @CallSuper
150 | protected synchronized final boolean onResult(final @NonNull String permission, int result) {
151 | if (result == PackageManager.PERMISSION_GRANTED) {
152 | return onResult(permission, Permissions.GRANTED);
153 | } else {
154 | return onResult(permission, Permissions.DENIED);
155 | }
156 | }
157 |
158 | /**
159 | * This method is called when a particular permission has changed.
160 | * This method will be called for all permissions, so this method determines
161 | * if the permission affects the state or not and whether it can proceed with
162 | * calling onGranted or if onDenied should be called.
163 | *
164 | * @param permission the permission that changed.
165 | * @param result the result for that permission.
166 | * @return this method returns true if its primary action has been completed
167 | * and it should be removed from the data structure holding a reference to it.
168 | */
169 | @CallSuper
170 | protected synchronized final boolean onResult(final @NonNull String permission, Permissions result) {
171 | mPermissions.remove(permission);
172 | boolean onResult = false;
173 | if (result == Permissions.GRANTED) {
174 | getSchedule().scheduleDirect(new Runnable() {
175 | @Override
176 | public void run() {
177 | PermissionsResultAction.this.onGranted(permission);
178 | }
179 | });
180 | } else if (result == Permissions.DENIED) {
181 | getSchedule().scheduleDirect(new Runnable() {
182 | @Override
183 | public void run() {
184 | PermissionsResultAction.this.onDenied(permission);
185 | }
186 | });
187 | } else if (result == Permissions.NOT_FOUND) {
188 | if (shouldIgnorePermissionNotFound(permission)) {
189 | getSchedule().scheduleDirect(new Runnable() {
190 | @Override
191 | public void run() {
192 | PermissionsResultAction.this.onGranted(permission);
193 | }
194 | });
195 | } else {
196 | getSchedule().scheduleDirect(new Runnable() {
197 | @Override
198 | public void run() {
199 | PermissionsResultAction.this.onDenied(permission);
200 | }
201 | });
202 | }
203 | } else if (result == Permissions.USER_DENIED_FOREVER) {
204 | getSchedule().scheduleDirect(new Runnable() {
205 | @Override
206 | public void run() {
207 | PermissionsResultAction.this.onDeniedForever(permission);
208 | }
209 | });
210 | }
211 |
212 | //标记不被通过的权限
213 | if (result == Permissions.DENIED || (result == Permissions.NOT_FOUND && !shouldIgnorePermissionNotFound(permission))) {
214 | mDeniedPermissions.add(permission);
215 | }
216 | if (mPermissions.isEmpty()) {
217 | getSchedule().scheduleDirect(new Runnable() {
218 | @Override
219 | public void run() {
220 | if (mDeniedPermissions.isEmpty()) {
221 | PermissionsResultAction.this.onSuccess();
222 | } else {
223 | final String[] deniedPermissions = (String[]) mDeniedPermissions.toArray(
224 | new String[mDeniedPermissions.size()]);
225 | PermissionsResultAction.this.onFailure(deniedPermissions);
226 | }
227 | //重置不被通过的权限存储
228 | mDeniedPermissions.clear();
229 | }
230 | });
231 | onResult = true;
232 | }
233 | return onResult;
234 | }
235 |
236 | /**
237 | * This method registers the PermissionsResultAction object for the specified permissions
238 | * so that it will know which permissions to look for changes to. The PermissionsResultAction
239 | * will then know to look out for changes to these permissions.
240 | *
241 | * @param perms the permissions to listen for
242 | */
243 | @SuppressWarnings("WeakerAccess")
244 | @CallSuper
245 | protected synchronized final void registerPermissions(@NonNull String[] perms) {
246 | Collections.addAll(mPermissions, perms);
247 | }
248 |
249 | /**
250 | * 获取执行权限回调的线程调度器
251 | *
252 | * @return
253 | */
254 | protected synchronized Scheduler getSchedule() {
255 | return null == mLooper ? AndroidSchedulers.mainThread() : AndroidSchedulers.from(mLooper);
256 | }
257 |
258 | protected int getRequestCode() {
259 | return mRequestCode;
260 | }
261 | }
--------------------------------------------------------------------------------
/simplepermission/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | simplePermission
3 |
4 |
--------------------------------------------------------------------------------
/simplepermission_ano/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/simplepermission_ano/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java-library'
2 | apply plugin: 'com.novoda.bintray-release'
3 | apply plugin: 'maven'
4 |
5 | //加载资源
6 | Properties properties = new Properties()
7 | InputStream inputStream = project.rootProject.file('local.properties').newDataInputStream();
8 | properties.load(inputStream)
9 |
10 | publish {
11 | bintrayUser = properties.getProperty("bintrayUser")
12 | bintrayKey = properties.getProperty("bintrayKey")
13 | userOrg = 'ykbjson' // bintray注册的用户名
14 | groupId = rootProject.ext.bintray.group
15 | artifactId = 'simplepermission_ano'// bintray创建的package
16 | publishVersion = rootProject.ext.bintray.anoVersion
17 | desc = 'SimplePermission权限申请库注解'
18 | }
19 |
20 | dependencies {
21 | implementation fileTree(dir: 'libs', include: ['*.jar'])
22 | }
23 |
24 | sourceCompatibility = "1.7"
25 | targetCompatibility = "1.7"
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/simplepermission_ano/src/main/java/com/ykbjson/lib/simplepermission/ano/PermissionNotify.java:
--------------------------------------------------------------------------------
1 | package com.ykbjson.lib.simplepermission.ano;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * Desription:onRequestPermissionsResult方法回调的接收者
10 | * Creator:yankebin
11 | * CreatedAt:2018/10/29
12 | */
13 | @Retention(RetentionPolicy.RUNTIME)
14 | @Target(ElementType.TYPE)
15 | public @interface PermissionNotify {
16 | }
17 |
--------------------------------------------------------------------------------
/simplepermission_ano/src/main/java/com/ykbjson/lib/simplepermission/ano/PermissionRequest.java:
--------------------------------------------------------------------------------
1 | package com.ykbjson.lib.simplepermission.ano;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * Desription:请求权限的方法注解
10 | * Creator:yankebin
11 | * CreatedAt:2018/10/29
12 | */
13 | @Retention(RetentionPolicy.RUNTIME)
14 | @Target(ElementType.METHOD)
15 | public @interface PermissionRequest {
16 |
17 | /**
18 | * 申请权限的code,在权限回调的时候可以根据code知道哪些权限被授予或拒绝
19 | */
20 | int requestCode() default 0;
21 |
22 | /**
23 | * 要申请的权限数组
24 | */
25 | String[] requestPermissions() default {""};
26 |
27 | /**
28 | * 是否需要在申请成功后再次执行代码逻辑
29 | */
30 | boolean needReCall() default false;
31 | }
32 |
--------------------------------------------------------------------------------