├── .gitignore ├── README.md ├── blogs ├── articles │ ├── custom_update.md │ ├── first_not_update.md │ ├── force_update.md │ ├── ignore_update.md │ ├── manual_update.md │ └── umeng_update_best_practice.md └── images │ ├── update1.png │ ├── update2.png │ └── update3.png ├── fb └── v4.3 │ ├── res │ └── layout │ │ ├── umeng_fb_activity_contact.xml │ │ ├── umeng_fb_activity_conversation.xml │ │ ├── umeng_fb_list_header.xml │ │ ├── umeng_fb_list_item.xml │ │ └── umeng_fb_new_reply_alert_dialog.xml │ └── src │ └── com │ └── umeng │ └── fb │ ├── ContactActivity.java │ └── ConversationActivity.java └── update ├── README.md ├── default ├── README.md ├── light.png └── res │ ├── drawable │ ├── umeng_update_button_cancel_normal.xml │ ├── umeng_update_button_cancel_selector.xml │ ├── umeng_update_button_cancel_tap.xml │ ├── umeng_update_button_ok_normal.xml │ ├── umeng_update_button_ok_selector.xml │ ├── umeng_update_button_ok_tap.xml │ ├── umeng_update_dialog_bg.xml │ └── umeng_update_wifi_disable.png │ ├── layout │ └── umeng_update_dialog.xml │ ├── values-zh │ ├── umeng_common_strings.xml │ └── umeng_update_string.xml │ └── values │ ├── umeng_common_strings.xml │ └── umeng_update_string.xml ├── libs ├── armeabi-v7a │ └── libbspatch.so ├── armeabi │ └── libbspatch.so ├── mips │ └── libbspatch.so └── x86 │ └── libbspatch.so └── white-blue ├── README.md ├── res ├── drawable │ ├── umeng_update_button_cancel_normal.xml │ ├── umeng_update_button_cancel_selector.xml │ ├── umeng_update_button_cancel_tap.xml │ ├── umeng_update_button_ok_normal.xml │ ├── umeng_update_button_ok_selector.xml │ ├── umeng_update_button_ok_tap.xml │ ├── umeng_update_dialog_bg.xml │ ├── umeng_update_title_bg.xml │ └── umeng_update_wifi_disable.png ├── layout │ └── umeng_update_dialog.xml ├── values-zh │ ├── umeng_common_strings.xml │ └── umeng_update_string.xml └── values │ ├── umeng_common_strings.xml │ └── umeng_update_string.xml └── white-blue.png /.gitignore: -------------------------------------------------------------------------------- 1 | # built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | 15 | # Local configuration file (sdk path, etc) 16 | local.properties 17 | 18 | # Eclipse project files 19 | .classpath 20 | .project 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 友盟组件主题 2 | ======================= 3 | 4 | 此工程提供针对友盟 组件 的多种主题样式。 5 | 6 | 1. [双向反馈](https://github.com/ntop001/umeng-android-sdk-theme/tree/master/fb) 7 | 2. [自动更新](https://github.com/ntop001/umeng-android-sdk-theme/tree/master/update) 8 | -------------------------------------------------------------------------------- /blogs/articles/custom_update.md: -------------------------------------------------------------------------------- 1 | ## 自定义更新 2 | 3 | 使用友盟自动更新模块实现自定义更新的示例:
4 | 有时候您可能会要求使用自定义的UI方式来展示更新提示,这里给出使用自定义更新的样例,下面使用的是友盟默认的布局的实现,实际您可以根据您自己的需要进行相应的更改。 5 | 6 | 在Activity的`onCreate`方法中设置更新回调: 7 | 8 | ```java 9 | @Override 10 | protected void onCreate(Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | ...... 13 | final Context mContext = this; 14 | // 设置禁止自动弹窗,自定义弹窗操作 15 | UmengUpdateAgent.setUpdateAutoPopup(false); 16 | // 设置更新回调,自主处理更新 17 | UmengUpdateAgent.setUpdateListener(new UmengUpdateListener() { 18 | 19 | @Override 20 | public void onUpdateReturned(int updateStatus, 21 | UpdateResponse updateInfo) { 22 | switch (updateStatus) { 23 | case UpdateStatus.Yes: // 检测到有更新 24 | showUpdateDialog(updateInfo); 25 | break; 26 | case UpdateStatus.No: // 检测到没有更新 27 | Toast.makeText(mContext, "没有更新", Toast.LENGTH_SHORT).show(); 28 | break; 29 | case UpdateStatus.NoneWifi: // 当前不是Wifi环境 30 | Toast.makeText(mContext, "没有wifi连接, 只在wifi下更新", 31 | Toast.LENGTH_SHORT).show(); 32 | break; 33 | case UpdateStatus.Timeout: // 检测超时 34 | Toast.makeText(mContext, "超时", Toast.LENGTH_SHORT).show(); 35 | break; 36 | } 37 | } 38 | }); 39 | UmengUpdateAgent.update(this); 40 | } 41 | ``` 42 | 定义方法`showUpdateDialog`展示更新提示: 43 | ```java 44 | private void showUpdateDialog(UpdateResponse updateInfo) { 45 | //如果版本已经被忽略,不弹框 46 | if (UmengUpdateAgent.isIgnore(this, updateInfo)) { 47 | return; 48 | } 49 | //获取下载完的文件,如果未下载则为null 50 | final File file = UmengUpdateAgent.downloadedFile(this, updateInfo); 51 | boolean isDownloaded = file != null; 52 | //创建更新对话框 53 | createDialog(updateInfo, isDownloaded, file).show(); 54 | } 55 | ``` 56 | 定义方法`createDialog`创建更新对话框: 57 | ```java 58 | /** 59 | * 创建更新对话框 60 | * @param updateInfo 更新信息 61 | * @param isDownloaded 是否已经下载 62 | * @param file 下载完的文件,如果未下载为null 63 | * @return 更新对话框 64 | */ 65 | private Dialog createDialog(final UpdateResponse updateInfo, 66 | boolean isDownloaded, final File file) { 67 | final boolean[] isIgnore = { false }; 68 | final int[] result = { UpdateStatus.NotNow }; 69 | final Context context = this; 70 | 71 | // 如果您的应用是全屏的,可以在这里设置Dialog也为全屏 72 | final Dialog dialog = new Dialog(context, 73 | android.R.style.Theme_Translucent_NoTitleBar); 74 | View v = LayoutInflater.from(context).inflate( 75 | R.layout.umeng_update_dialog, null); 76 | 77 | // 忽略勾选框的状态回调 78 | OnCheckedChangeListener cl = new OnCheckedChangeListener() { 79 | 80 | @Override 81 | public void onCheckedChanged(CompoundButton buttonView, 82 | boolean isChecked) { 83 | isIgnore[0] = isChecked; 84 | } 85 | }; 86 | // 点击回调,记录用户的不同选择 87 | OnClickListener ll = new OnClickListener() { 88 | 89 | @Override 90 | public void onClick(View v) { 91 | if (R.id.umeng_update_id_ok == v.getId()) { 92 | result[0] = UpdateStatus.Update; 93 | } else if (R.id.umeng_update_id_ignore == v.getId()) { 94 | result[0] = UpdateStatus.Ignore; 95 | } else if (isIgnore[0]) { 96 | result[0] = UpdateStatus.Ignore; 97 | } 98 | dialog.dismiss(); 99 | } 100 | 101 | }; 102 | // 对话框消失回调,处理用户的不同选择 103 | dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { 104 | @Override 105 | public void onDismiss(DialogInterface dialogInterface) { 106 | switch (result[0]) { 107 | case UpdateStatus.Update: 108 | // 用户选择更新 109 | if (file == null) { 110 | //开始下载 111 | UmengUpdateAgent.startDownload(context, updateInfo); 112 | } else { 113 | //开始安装 114 | UmengUpdateAgent.startInstall(context, file); 115 | } 116 | break; 117 | case UpdateStatus.Ignore: 118 | // 用户选择忽略 119 | UmengUpdateAgent.ignoreUpdate(context, updateInfo); 120 | break; 121 | case UpdateStatus.NotNow: 122 | // 用户选择取消 123 | break; 124 | } 125 | } 126 | }); 127 | 128 | // 获得网络连接服务 129 | ConnectivityManager connManager = (ConnectivityManager) context 130 | .getSystemService(Context.CONNECTIVITY_SERVICE); 131 | // 获取WIFI网络连接状态 132 | State state = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI) 133 | .getState(); 134 | // 如果正在使用WIFI网络或已经下载完成不显示无Wifi的图标 135 | int visibility = (State.CONNECTED == state) || isDownloaded ? View.GONE 136 | : View.VISIBLE; 137 | v.findViewById(R.id.umeng_update_wifi_indicator).setVisibility( 138 | visibility); 139 | 140 | v.findViewById(R.id.umeng_update_id_ok).setOnClickListener(ll); 141 | v.findViewById(R.id.umeng_update_id_cancel).setOnClickListener(ll); 142 | v.findViewById(R.id.umeng_update_id_ignore).setOnClickListener(ll); 143 | v.findViewById(R.id.umeng_update_id_close).setOnClickListener(ll); 144 | ((CheckBox) v.findViewById(R.id.umeng_update_id_check)) 145 | .setOnCheckedChangeListener(cl); 146 | // 设置对话框显示文本 147 | String content = updateContentString(updateInfo, isDownloaded); 148 | TextView tv = (TextView) v.findViewById(R.id.umeng_update_content); 149 | tv.requestFocus(); 150 | tv.setText(content); 151 | 152 | dialog.setContentView(v); 153 | 154 | return dialog; 155 | } 156 | ``` 157 | 定义方法`updateContentString`处理更新信息,转换为更新对话框显示文本: 158 | ```java 159 | /** 160 | * 根据更新信息编排对话框显示文本 161 | * 162 | * @param updateInfo 163 | * 更新信息 164 | * @param isDownloaded 165 | * 是否已经下载 166 | * @return 更新对话框显示文本 167 | */ 168 | public String updateContentString(UpdateResponse updateInfo, 169 | boolean isDownloaded) { 170 | String versionPrefix = getString(R.string.UMNewVersion); 171 | String sizePrefix = getString(R.string.UMTargetSize); 172 | String deltaPrefix = getString(R.string.UMUpdateSize); 173 | String updateLogPrefix = getString(R.string.UMUpdateContent); 174 | String installApk = getString(R.string.UMDialog_InstallAPK); 175 | // 已经下载的情况 176 | if (isDownloaded) { 177 | return String.format("%s %s\n" + "%s\n\n" + "%s\n" + "%s\n", 178 | versionPrefix, updateInfo.version, installApk, 179 | updateLogPrefix, updateInfo.updateLog); 180 | } 181 | 182 | String deltaContent; 183 | // 增量更新和全量更新的情况 184 | if (updateInfo.delta) { 185 | deltaContent = String.format("\n%s %s", deltaPrefix, 186 | getFileSizeDescription(updateInfo.size)); 187 | } else { 188 | deltaContent = ""; 189 | } 190 | // 未下载的情况 191 | return String.format("%s %s\n" + "%s %s%s\n\n" + "%s\n" + "%s\n", 192 | versionPrefix, updateInfo.version, sizePrefix, 193 | getFileSizeDescription(updateInfo.target_size), deltaContent, 194 | updateLogPrefix, updateInfo.updateLog); 195 | } 196 | ``` 197 | 定义方法`getFileSizeDescription`处理文件大小,格式化为需要显示的文本: 198 | ```java 199 | /** 200 | * 将字节数转换为用于显示的文件大小格式 201 | * 202 | * @param size 203 | * 文件字节数 204 | * @return 格式化后的文件大小文本 205 | */ 206 | public static String getFileSizeDescription(String size) { 207 | String value = ""; 208 | long bytes = 0; 209 | try { 210 | bytes = Long.valueOf(size).longValue(); 211 | } catch (NumberFormatException e) { 212 | return size; 213 | } 214 | if (bytes < 1024) { 215 | value = (int) bytes + "B"; 216 | } else if (bytes < 1048576) { 217 | DecimalFormat df = new DecimalFormat("#0.00"); 218 | value = df.format((float) bytes / 1024.0) + "K"; 219 | } else if (bytes < 1073741824) { 220 | DecimalFormat df = new DecimalFormat("#0.00"); 221 | value = df.format((float) bytes / 1048576.0) + "M"; 222 | } else { 223 | DecimalFormat df = new DecimalFormat("#0.00"); 224 | value = df.format((float) bytes / 1073741824.0) + "G"; 225 | } 226 | return value; 227 | } 228 | ``` 229 | -------------------------------------------------------------------------------- /blogs/articles/first_not_update.md: -------------------------------------------------------------------------------- 1 | ## 首次启动不更新 2 | 3 | 有的时候,开发者会希望在应用在下载后第一次启动时不要启动自动更新,这样即使下载的不是最近版本也不会在首次启动时提醒更新。 4 | 5 | 在应用程序入口`Activity`里的`OnCreate()`方法中调用 6 | ```java 7 | @Override 8 | protected void onCreate(Bundle savedInstanceState) { 9 | super.onCreate(savedInstanceState); 10 | SharedPreferences sharedPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE); 11 | boolean isFirstStart = sharedPreferences.getBoolean(KEY_FIRST_START, true); 12 | if (isFirstStart) { 13 | sharedPreferences.edit().putBoolean(KEY_FIRST_START, false).commit(); 14 | } else { 15 | UmengUpdateAgent.update(this); 16 | } 17 | ``` 18 | 其中`SHARED_PREFERENCES_NAME`为sharedPreference文件名,`KEY_FIRST_START`为判断是否为第一次启动值的key 19 | -------------------------------------------------------------------------------- /blogs/articles/force_update.md: -------------------------------------------------------------------------------- 1 | ## 强制更新 2 | 3 | 有的时候,开发者会想要用户必须进行更新,下面给出使用友盟自动更新模块(V2.3)进行强制更新的示例: 4 | 5 | 修改`umeng_update_dialog.xml`中相关控件 6 | 7 | ```xml 8 |