硕士生
 
- 金币
- 679
- 好评
- 13
- 信誉
- 100
|
本帖最后由 青春风暴 于 2020-5-24 18:24 编辑
清羽弹窗用起来很方便,但它的代码经过了加密
导致不便于修改,而且新手想要弄清楚它的原理也是困难重重
于是我模仿着写了一个类似的,顺便增加了sharedpreferences以及跳转Activity功能
同时增加了为每个弹窗设置别名的功能,以确保不同的弹窗之间“不再提示”的缓存数据不会互相干扰
这里附上一个用于测试的Demo:https://lanzous.com/icrksob
弹窗配置链接:https://share.weiyun.com/5Hh5stU
下面附上源代码,供感兴趣的朋友们研究、学习
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Process;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.URL;
import static android.content.Context.MODE_PRIVATE;
- public class MyOnlineDialog extends AsyncTask {
- private Context mContext;
- private String url, NAME = "dialog_version";
- private MyDialogButton[] button = new MyDialogButton[3];
- private int version;
- public MyOnlineDialog(Context context, String url) {
- this.mContext = context;
- this.url = url;
- }
- /*如果一个软件中需要添加不同的弹窗,可以用这个构造方法
- 这样可以使得A界面的弹窗被用户点了“不再提示”后,不会影响到其他界面的弹窗继续弹出*/
- public MyOnlineDialog(Context context, String url, String name) {
- this.mContext = context;
- this.url = url;
- this.NAME = name + "_dialog_version";
- }
- public void init() {
- try {
- Class.forName("android.os.AsyncTask");
- execute();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- }
- //从链接中获取弹窗的配置信息
- private String initConfig() {
- try {
- HttpURLConnection connection = (HttpURLConnection) (new URL(url)).openConnection();
- connection.setRequestMethod("GET");
- connection.setUseCaches(false);
- connection.setReadTimeout(20000);
- connection.setConnectTimeout(20000);
- connection.setInstanceFollowRedirects(false);
- connection.setRequestProperty("User-Agent"
- , "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7");
- if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
- BufferedReader reader = new BufferedReader(new InputStreamReader(
- connection.getInputStream(), "UTF-8"));
- StringBuilder builder = new StringBuilder();
- String config;
- while (true) {
- String s = reader.readLine();
- if (s == null) {
- config = builder.toString();
- break;
- }
- builder.append(s);
- }
- //截取出弹窗的配置信息
- config = config.split("〈Configuration〉")[2]
- .replace(" ", " ")
- .replace("\\u003C", "<")
- .replace("<p>", "")
- .replace("</p>", "\n")
- .replace("<br />", "\n");
- //这里可以借用这个弹窗来保存一些数据
- if (config.contains("〈SharedPreferences〉")) {
- setSharedPreferences(config.split("〈SharedPreferences〉")[1].trim());
- }
- return config;
- } else return "";
- } catch (Exception e) {
- e.printStackTrace();
- return "";
- }
- }
- private void setSharedPreferences(String sp) {
- String[] sharedPreferences = sp.split("◎");
- if (0 < sharedPreferences.length) {
- SharedPreferences.Editor editor = mContext.getSharedPreferences("data", MODE_PRIVATE).edit();
- for (String s : sharedPreferences) {
- String key = s.split("〈Key〉")[1].trim();
- String value = s.split("〈Value〉")[1].trim();
- if (!s.contains("〈Type〉")) {
- editor.putString(key, value);
- } else {
- //保存数据时有多种数据类型可供选择,若没有选定类型,则默认为String类型
- String type = s.split("〈Type〉")[1];
- if (type.toLowerCase().contains("int")) {
- editor.putInt(key, Integer.parseInt(value));
- } else if (type.toLowerCase().contains("bool")) {
- editor.putBoolean(key, value.toLowerCase().contains("true"));
- } else if (type.toLowerCase().contains("float")) {
- editor.putFloat(key, Float.parseFloat(value));
- } else if (type.toLowerCase().contains("long")) {
- editor.putLong(key, Long.parseLong(value));
- } else {
- editor.putString(key, value);
- }
- }
- }
- editor.apply();
- }
- }
- private void onclick(DialogInterface dialog, int which) {
- button[-which - 1].execute();
- setCancelable(dialog, true);
- }
- //这个方法通过反射将弹窗设定为不可取消,当然必要时也可以将弹窗取消
- private void setCancelable(DialogInterface dialog, Boolean cancelable) {
- try {
- Field field = dialog.getClass().getSuperclass().getDeclaredField("mShowing");
- field.setAccessible(true);
- field.set(dialog, cancelable);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- @Override
- protected Object doInBackground(Object[] objects) {
- return initConfig();
- }
- protected void onPostExecute(Object var1) {
- String config = (String) var1;
- super.onPostExecute(config);
- /*从本地获取版本号记录
- 如果版本号为k的弹窗被用户点击过“不再显示”,那此时只有版本号不小于k+1的弹窗才会显示*/
- if (config.split("〈isEnabled〉")[1].contains("true")) {
- SharedPreferences preferences = mContext.getSharedPreferences("data", MODE_PRIVATE);
- int localVersion = preferences.getInt(NAME, 0);
- version = Integer.parseInt(config.split("〈Version〉")[1].trim());
- if (version > localVersion) show(config);
- }
- }
- //构造并弹出弹窗
- private void show(String config) {
- String title = config.split("〈Title〉")[1].trim();
- String message = config.split("〈Message〉")[1].trim();
- boolean cancelable = config.split("〈Cancelable〉")[1].contains("true");
- button[0] = new MyDialogButton(config.split("〈Positive_Button〉")[1]);
- button[1] = new MyDialogButton(config.split("〈Negative_Button〉")[1]);
- button[2] = new MyDialogButton(config.split("〈Neutral_Button〉")[1]);
- AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
- builder.setTitle(title).setMessage(message);
- if (button[0].isEnabled) builder.setPositiveButton(button[0].text, this::onclick);
- if (button[1].isEnabled) builder.setNegativeButton(button[1].text, this::onclick);
- if (button[2].isEnabled) builder.setNeutralButton(button[2].text, this::onclick);
- AlertDialog alertDialog = builder.create();
- alertDialog.show();
- //将弹窗设置为不可取消的
- if (!cancelable) {
- setCancelable(alertDialog, false);
- }
- }
- //弹窗按钮内部类
- private class MyDialogButton {
- boolean isEnabled;
- String text, event;
- MyDialogButton(String config) {
- isEnabled = config.split("〈isEnabled〉")[1].contains("true");
- text = config.split("〈Text〉")[1].trim();
- event = config.split("〈Event〉")[1].trim();
- }
- void execute() {
- if (event.contains("〈Toast〉")) {
- Toast.makeText(mContext, event.split("〈Toast〉")[1].trim(), Toast.LENGTH_LONG).show();
- }
- if (event.contains("〈QQGroup〉")) {
- mContext.startActivity(new Intent(Intent.ACTION_VIEW
- , Uri.parse("mqqapi://card/show_pslcard?&uin=" +
- event.split("〈QQGroup〉")[1].trim() + "&card_type=group")));
- } else if (event.contains("〈QQ〉")) {
- mContext.startActivity(new Intent(Intent.ACTION_VIEW
- , Uri.parse("mqqwpa://im/chat?chat_type=wpa&uin=" +
- event.split("〈QQ〉")[1].trim())));
- } else if (event.contains("〈Url〉")) {
- String url = event.split("〈Url〉")[1].trim();
- if (!url.startsWith("http")) url = "https://" + url;
- mContext.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
- } else if (event.contains("〈Activity〉")) {
- try {
- mContext.startActivity(new Intent(mContext, Class.forName(
- event.split("〈Activity〉")[1].trim())));
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- }
- if (event.contains("〈-Dismiss-〉")) {
- mContext.getSharedPreferences("data", MODE_PRIVATE)
- .edit().putInt(NAME, version).apply();
- }
- if (event.contains("〈-Exit-〉")) Process.killProcess(Process.myPid());
- }
- }
- }
复制代码
下面是调用示例:
- //整个软件只植入这一个弹窗的调用方法
- new MyOnlineDialog(this, "https://share.weiyun.com/XXXXX").init();
- //植入多个弹窗的调用方法
- //比如这个要植入在主界面
- new MyOnlineDialog(this, "https://share.weiyun.com/XXXXX", "主界面").init();
- //这个则要植入在测试页
- new MyOnlineDialog(this, "https://share.weiyun.com/XXXXX", "测试页").init();
复制代码
【5月24日更新】非常抱歉,之前有个东西忘说了。
中间setPositiveButton那几句(也就是this::onclick那里),为了代码整洁美观,我就用了Lambda表达式。如果你直接复制,可能会报错。这个需要在项目的Module里设置一下Target Compatibility,让它引用JDK1.8。这个错误,如果按快捷键应该也是会自动跳出解决方案的
具体可以参考:https://blog.csdn.net/ocean20/article/details/83790755 |
-
查看全部评分
总评分:好评 +3
金币 +3
|