如何使用注解生成WXEntryActivity?
在Android中使用注解时,需要创建java模块,否则无法导入javax.annotation.processing.AbstractProcessor;
相关依赖。
1. android注解配置
1. 使用annotationProcessor
设置参数
a) /gradle/wrapper/gradle-wrapper.properties
distributionUrl = https\://services.gradle.org/distributions/gradle-4.4-all.zip
b) 配置annotationProcessor
buildscript {
repositories {
// Gradle 4.1 and higher include support for Google's Maven repo using
// the google() method. And you need to include this repo to download
// Android plugin 3.0.0 or higher.
google()
...
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.0'
}
}
android {
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments = [
key1 : 'key1Value',
key2 : 'key2Value'
]
}
}
}
}
dependencies {
annotationProcessor 'xxx:xx:xxx'
}
2. 使用apt
方式设置参数
buildscript {
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
apply plugin: 'com.neenbedankt.android-apt'
apt {
arguments {
key1 'key1Value'
key2 'key2Value'
}
}
dependencies {
apt 'xxx:xx:xxx'
}
3. 在注解解析器中获取传入参数
processingEnvironment.getOptions()
获取传递给注解的参数.
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class AnnonationProcessor extends AbstractProcessor {
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
Map<String, String> options = processingEnvironment.getOptions();
}
}
4. 配置注解生效
在resources中添加该文件
resources/META-INF/services/javax.annotation.processing.Processor
,然后在文件内容中添加创建的注解处理器类,如下所示:$ cat resources/META-INF/services/javax.annotation.processing.Processor com.xxx.yyy.AnnonationProcessor
2. 使用注解自动创建WXEntryActivity
我们知道使用微信分享或者支付sdk时,微信会指定接收结果的回调Activity包名固定为${packageName}.wxapi
,这样我们修改包名创建马甲包时就会比较麻烦,通过使用注解自动生成指定包名的activity可以很好的解决这个问题。
1. 创建注解
在注解中指定包名,用于创建特定包名的WXEntryActivity。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface WXEntryActivityHandler {
String packageName();
}
2. 创建注解处理器
注解处理器
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.Writer; import java.util.Collections; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; @SupportedSourceVersion(SourceVersion.RELEASE_7) public class AnnonationProcessor extends AbstractProcessor { private static final String WX_ENTRY_ACTIVITY_TEMPLATE_PATH = "/WXEntryActivity.tmpl"; @Override public Set<String> getSupportedAnnotationTypes() { return Collections.singleton(WXEntryActivityHandler.class.getCanonicalName()); } @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { super.init(processingEnvironment); } @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { Set<? extends Element> elementsAnnotatedWith = roundEnvironment.getElementsAnnotatedWith(WXEntryActivityHandler.class); for (Element e : elementsAnnotatedWith) { generateShareHandlerCode(e); } return true; } private void generateShareHandlerCode(Element element) { if (!(element instanceof TypeElement)) { return; } WXEntryActivityHandler annotation = element.getAnnotation(WXEntryActivityHandler.class); if (annotation == null) { return; } String wxEntryActivityTmplText = readAll(WX_ENTRY_ACTIVITY_TEMPLATE_PATH); if (wxEntryActivityTmplText == null) { return; } TypeElement typeElement = (TypeElement) element; String wechatHandler = typeElement.getQualifiedName().toString(); final String packageName = annotation.packageName(); if (packageName == null || "".equals(packageName.trim())) { String msg = "WXEntryActivityHandler.packageName() for " + wechatHandler + " cannot be null or empty."; processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg); throw new RuntimeException(msg); } final String wxapiPackageName = packageName + ".wxapi"; String generateCode = wxEntryActivityTmplText.replaceAll("%PACKAGE_NAME%", wxapiPackageName) .replaceAll("%WXEntryActivityCallbackImpl%", wechatHandler); try { JavaFileObject fileObject = processingEnv.getFiler().createSourceFile(wxapiPackageName + ".WXEntryActivity"); processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Creating " + fileObject.toUri()); Writer writer = fileObject.openWriter(); try { PrintWriter pw = new PrintWriter(writer); pw.print(generateCode); pw.flush(); } finally { writer.close(); } } catch (IOException x) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, x.toString()); } } private String readAll(String tmplPath) { try { BufferedReader reader = new BufferedReader(new InputStreamReader(AnnonationProcessor.class.getResourceAsStream(tmplPath), "utf-8")); StringBuilder text = new StringBuilder(); String line = null; while ((line = reader.readLine()) != null) { text.append(line); } reader.close(); text.trimToSize(); return text.toString(); } catch (Throwable e) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "readAll from " + tmplPath + " error; " + e); } return null; } }
模板代码
package %PACKAGE_NAME%; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import WXEntryActivityCallback; public class WXEntryActivity extends Activity { private WXEntryActivityCallback wxEntryActivityCallback = new %WXEntryActivityCallbackImpl%(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); wxEntryActivityCallback.onCreate(this, savedInstanceState); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); wxEntryActivityCallback.onNewIntent(this, intent); } @Override protected void onStart() { super.onStart(); wxEntryActivityCallback.onStart(); } @Override protected void onRestart() { super.onRestart(); wxEntryActivityCallback.onRestart(); } @Override protected void onResume() { super.onResume(); wxEntryActivityCallback.onResume(); } @Override protected void onPause() { super.onPause(); wxEntryActivityCallback.onPause(); } @Override protected void onStop() { super.onStop(); wxEntryActivityCallback.onStop(); } @Override protected void onDestroy() { super.onDestroy(); wxEntryActivityCallback.onDestroy(); } }
3. 注解的使用
package com.xxx.yyy;
@WXEntryActivityHandler(packageName = BuildConfig.APPLICATION_ID)
public class WexinAPIEventHandler implements WXEntryActivityCallback, IWXAPIEventHandler {
private static final String TAG = "WexinAPIEventHandler";
private IWXAPI mWXApi;
private Activity wxEntryActivity;
public void onCreate(Activity wxEntryActivity, Bundle savedInstanceState) {
this.wxEntryActivity = wxEntryActivity;
mWXApi = WXAPIFactory.createWXAPI(wxEntryActivity, BuildConfig.WX_APP_ID);
mWXApi.registerApp(BuildConfig.WX_APP_ID);
try {
mWXApi.handleIntent(wxEntryActivity.getIntent(), this);
} catch (Throwable e) {
Log.e(TAG, "onCreate error", e);
}
}
public void onNewIntent(Activity wxEntryActivity, Intent intent) {
try {
mWXApi.handleIntent(intent, this);
} catch (Throwable e) {
Log.e(TAG, "onCreate onNewIntent", e);
}
}
@Override
public void onReq(BaseReq baseReq) {
Log.e(TAG, " baseReq-type:" + baseReq.getType());
WXMediaMessage wxMsg = ((ShowMessageFromWX.Req) baseReq).message;
WXAppExtendObject obj = (WXAppExtendObject) wxMsg.mediaObject;
StringBuffer msg = new StringBuffer(); // 组织一个待显示的消息内容
msg.append("description: ");
msg.append(wxMsg.description);
msg.append("\n");
msg.append("extInfo: ");
msg.append(obj.extInfo);
msg.append("\n");
msg.append("filePath: ");
msg.append(obj.filePath);
Log.e(TAG, " baseReq-title:" + wxMsg.title + ":msg:" + msg.toString());
switch (baseReq.getType()) {
case ConstantsAPI.COMMAND_GETMESSAGE_FROM_WX:
Log.e(TAG, " baseReq-title:1");
break;
case ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX:
Log.e(TAG, " baseReq-title:2");
break;
default:
break;
}
}
@Override
public void onResp(BaseResp baseResp) {
String result = "";
Log.e(TAG, "baseresp.getType:" + baseResp.getType() + ":transaction:" + baseResp.transaction);
switch (baseResp.errCode) {
case BaseResp.ErrCode.ERR_OK:
result = "发送成功";
break;
case BaseResp.ErrCode.ERR_USER_CANCEL:
result = "发送取消";
break;
case BaseResp.ErrCode.ERR_AUTH_DENIED:
result = "发送被拒绝";
break;
case BaseResp.ErrCode.ERR_UNSUPPORT:
result = "不支持错误";
break;
default:
result = "发送返回";
break;
}
Log.e(TAG, "baseresp.getType-id:" +
Log.e(TAG, "baseresp.getType-result:" + result + "");
this.wxEntryActivity.finish();
}
@Override
public void onStart() {
Log.e(TAG, "onStart");
}
@Override
public void onRestart() {
Log.e(TAG, "onRestart");
}
@Override
public void onResume() {
Log.e(TAG, "onResume");
}
@Override
public void onPause() {
Log.e(TAG, "onPause");
}
@Override
public void onStop() {
Log.e(TAG, "onStop");
}
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy");
}
}
4. 代码生成
通过gradle执行compileDebugJavaWithJavac
,注解就会自动生成com.xxx.yyy.wxapi.WXEntryActivity
类,最后在AndroidManifest中配置WXEntryActivity即可。
<activity
android:name="${applicationId}.wxapi.WXEntryActivity"
android:exported="true"
android:screenOrientation="portrait" />