友盟统计怎么算新增用户 android
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了友盟统计怎么算新增用户 android相关的知识,希望对你有一定的参考价值。
android 统计分析 SDK使用指南1. 建立App,下载SDK
登录你的帐号后,看到友盟的管理后台,点击"+添加新应用",进入新应用信息填写的页面。
App建立成功后,可以获得该App的AppKey,以及最新的开发指南和SDK文件。
可在 这里 下载SDK,包含开发文档,demo程序和jar包。
说明:在新应用信息填写中,请尽量填写真实的信息。您可以通过友盟统计分析平台的特性节省重复建立App的时间。
如果您要对App不同的发布渠道进行统计,不需要创建新App,请使用分发渠道分析,通过分发渠道分析,您可以更方便的对比数据。
2. 实现基本的使用基本统计实现本的页面跳转,机型,分辨率,地理位置 …的统计1. 导入umeng-sdk*.jar(简称SDK)下载最新版sdk的zip包,解压将其中的umeng-sdk.jar释放到本地目录,Eclipse用户右键您的工程根目录,选择Properties -> Java Build Path -> Libraries, 然后点击 Add External JARs... 选择指向 Analytics_Android_SDK_*.jar的路径,点击OK,即导入成功。
2. 配置 AndroidManifest.xml<manifest……><application ……> ……<activity ……/><meta-dataandroid:value="YOUR_APP_KEY"android:name="UMENG_APPKEY"></meta-data><meta-dataandroid:value="Channel ID"android:name="UMENG_CHANNEL"/></application><uses-sdkandroid:minSdkVersion="4"></uses-sdk><uses-permissionandroid:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission><uses-permissionandroid:name="android.permission.INTERNET"></uses-permission><uses-permissionandroid:name="android.permission.READ_PHONE_STATE"></uses-permission><uses-permissionandroid:name="android.permission.READ_LOGS"></uses-permission></manifest>说明:
META-DATA 用途
UMENG_APPKEY 用来定位该应用程序的唯一性。
UMENG_CHANNEL 用来标注应用推广渠道,区分新用户的来源来查看统计,您可以使用20位以内的英文和数字为渠道定名,替换value中的"Channel ID"。详见渠道统计。
权限 用途
INTERNET(必须) 允许应用程序联网,以便向我们的服务器端发送数据。
READ_PHONE_STATE(必须) 获取用户手机的IMEI,用来唯一的标识用户。(如果您的应用会运行在无法读取IMEI的平板上,我们会将mac地址作为用户的唯一标识,请添加权限: android.permission.ACCESS_WIFI_STATE )
ACCESS_NETWORK_STATE 检测网络状态,友盟SDK 1.6版本新增权限。
READ_LOGS 如果您想获得客户端crash的报告, 需要添加这个权限。具体见【使用错误报告】。
WRITE_EXTERNAL_STORAGE 如果您使用了友盟自动更新提醒功能,需添加这个权限,为了将更新的APK临时存在SD卡里。
3. 添加代码
添加引用: import com.umeng.analytics.MobclickAgent
注册 Activity: 在每个Activity的onResume方法中调用 MobclickAgent.onResume(Context), onPause方法中调用
MobclickAgent.onPause(Context)
publicvoid onResume() super.onResume(); MobclickAgent.onResume(this);publicvoid onPause() super.onPause(); MobclickAgent.onPause(this);API:public void onResume(Context context)
context 当前Activity的引用,这里请不要将全局的application context传入。
public void onPause(Context context)
context 当前Activity的引用,这里请不要将全局的application context传入。
API说明:
void onResume(Context context)
context 当前Activity引用
void onPause(Context context)
context 当前Activity引用
说明:
方法将会自动地从AndroidManifest.xml文件里读取Appkey。
确保在所有的activity中都调用 MobclickAgent.onResume() 和MobclickAgent.onPause()方法,这两个调用将不会阻塞应用程序的主线程,也不会影响应用程序的性能。
注意如果您的Activity之间有继承或者控制关系请不要同时在父和子Activity中重复添加onPause和onResume方法,否则会造成重复统计(eg.使用TabHost、TabActivity、ActivityGroup时)。
一个应用程序在多个activity之间连续切换时,将会被视为同一个session(启动)。
当用户两次使用之间间隔超过30秒时,将被认为是两个的独立的session(启动),例如用户回到home,或进入其他程序,经过一段时间后再返回之前的应用。
4. 测试
确认所需的权限都已经添加:INTERNET, READ_PHONE_STATE, (READ_LOGS, WRITE_EXTERNAL_STORAGE)
确认APPKEY已经正确的写入Androidmanifest.xml
确认所有的Activity中都调用了onResume和onPause方法
确认测试手机(或者模拟器)已成功连入网络
启动应用程序,几分钟之后您应该已经可以看到相应的报表.
3. 使用错误报告友盟统计分析工具,还可以帮助您捕捉用户在使用应用程序过程中出现的异常退出(FC), 并在应用程序下次启动时将错误报告发送给服务器。
1. 自动捕获异常退出(FC)
在AndroidManifest.xml里面添加权限android.permission.READ_LOGS
在程序的Main Activity(应用程序入口)的onCreate方法里调用MobclickAgent.onError(Context).
publicvoid onCreate(Bundle savedinstanceState) super.onCreate(savedInstanceState); MobclickAgent.onError(this); ...API:public void onError(Context context)
context 当前Activity的引用
说明:错误报告包含应用程序版本,操作系统版本和设备型号以及程序出现异常时的Stacktrace,这些数据将帮助您修正应用程序的Bug。
2. 手动发送错误报告如果您自己捕获了程序中的异常,但是依然希望,将这次异常信息发送到友盟的服务器,您可以调用下面的函数。
MobclickAgent.reportError(Context context,String error) API:public void reportError(Context context, String error)
context 当前Activity的引用
error 开发者手动捕获的错误信息
说明:手动发送的异常信息和自动捕获的异常信息一样,都会展示在错误报告面板。
4. 使用自定义事件除了基本统计分析功能外,我们还支持您自定义的事件分析,例如您可以统计游戏中通过不同关卡的人数,广告的点击次数或者视频被播放的次数等等。 使用自定义事件功能请先在网站应用管理后台(设置->编辑自定义事件)中添加相应的自定义事件后,服务器才会对相应的自定义事件请求进行处理。
1. 事件数量统计1. 在您希望跟踪的代码部分,调用如下方法:MobclickAgent.onEvent(Context context, String event_id);API:public void onEvent(Context context, String event_id)
context 当前Activity的引用
event_id 为当前统计的事件ID,注意要先在友盟网站上注册此事件ID。
示例:统计微博应用中“转发"事件发生的次数,那么在“转发"的函数里调用
MobclickAgent.onEvent(this, "Forward") 2. 记录事件的不同属性及取值,调用如下方法:MobclickAgent.onEvent(Context context, String event_id, Map<String,String>; map);API:public voidonEvent(Context context, String event_id, Map map)
context 当前Activity的引用
event_id 为当前统计的事件ID,注意要先在友盟网站上注册此事件ID。
map 为当前事件的属性和取值集合(key-value)
示例:MobclickAgent.onEvent(LoginActivity.this, "sinaLogin");
新浪用户登陆海知笔记
3. 考虑事件在一个属性上的取值,可以调用如下方法:MobclickAgent.onEvent(Context context, String event_id, String label);API:public void onEvent(Context context, String event_id, String label)
context 当前Activity的引用
event_id 为当前统计的事件ID,注意要先在友盟网站上注册此事件ID.
label 事件的一个属性描述
示例:统计游戏中“死亡"事件发生的关卡数,那么可以在死亡的函数里调用
MobclickAgent.onEvent(this, "player_dead","level");2. 事件时长统计有的事件是持续发生的,需要记录其持续的时间,这里提供两种解决方法。
1. 在事件开始和结束时分别调用onEventBegin和 onEventEnd两个函数。MobclickAgent.onEventBegin(Context context, String event_id);...MobclickAgent.onEventEnd(Context context, String event_id);API:public voidonEventBegin(Context context, String event_id)
public void onEventEnd(Context context, String event_id)
context 当前Activity引用
event_id 为当前统计的事件ID,注意要先在友盟网站上注册此事件ID.
public void onEventBegin(Context context, String event_id, String label)
public void onEventEnd(Context context, String event_id, String label)
context 当前Activity引用
event_id 为当前统计的事件ID,注意要先在友盟网站上注册此事件ID.
label 事件的一个属性描述
示例:跟踪播放音乐事件发生的总时间,在音乐播放开始时调用:
MobclickAgent.onEventBegin(this, "music_play");在音乐播放结束时调用:
MobclickAgent.onEventEnd(this, "music_play");2. 跟踪时长的事件包含多个属性,在事件开始和结束时分别调用onKVEventBegin和 onKVEventEnd两个函数MobclickAgent.onKVEventBegin(Context context, String event_id, Map<String,String> map, String ekvFlag);...MobclickAgent.onKVEventEnd(Context context, String event_id, String ekvFlag);API:public void onKVEventBegin(Context context, String event_id, Map map, String ekvFlag)
context 当前Activity引用
event_id 为当前统计的事件ID,注意要先在友盟网站上注册此事件ID.
map 为当前事件的属性和取值集合(key-value)
ekvFlag 事件标示符
public void onKVEventEnd(Context context, String event_id, String ekvFlag)
context 当前Activity引用
event_id 为当前统计的事件ID,注意要先在友盟网站上注册此事件ID
ekvFlag 事件标示符,ekvFlag 和 event_id 一起标示一个唯一事件,并不会被统计;对于同一个事件,在onKVEventBegin和onKVEventEnd 中要传递相同的event_id 和 flag
示例跟踪每种类型的音乐播放了多久,在音乐播放开始时调用
Map<String,String> music = new HashMap<String,String>(); music.put("type", "popular"); music.put("artist", "JJLin"); music.put("User_status", "registered");MobclickAgent.onKVEventBegin(this, "music",music,"m7");在音乐播放结束时调用:
MobclickAgent.onKVEventEnd(this, "music",music,"m7");3. 自己计算并上传event时长,在您想跟踪时长的代码部分,调用如下方法:MobclickAgent.onEventDuration(Context context, String event_id, long duration);orMobclickAgent.onEventDuration(Context context, String event_id,String label, long duration)orMobclickAgent.onEventDuration(Context context, String event_id, Map<String, String> map, long duration)API:public void onEventDuration(Context context, String event_id, long duration)
public void onEventDuration(Context context, String event_id,String label, long duration)
context 当前Activity引用
event_id 为当前统计的事件ID,注意要先在友盟网站上注册此事件ID
label 事件的一个属性描述
duration 事件持续时长,单位毫秒,您需要手动计算并传入时长,作为事件的时长参数
public void onEventDuration(Context context, String event_id, Map map, long duration)
context 当前Activity引用
event_id 为当前统计的事件ID,注意要先在友盟网站上注册此事件ID
map 为当前事件的属性和取值集合(key-value)
duration 事件持续时长,单位毫秒,您需要手动计算并传入时长,作为事件的时长参数
说明
时长是友盟统计的一个新功能,使用过程中可能会出现一些常见的错误,开发者应该尽量的避免,这里有一些可能出错的案例。
每个event的key不能超过10个,event ID、map中key和value都不能使用特殊字符,且长度不能超过255个字符(否则将截取前255个字符),“id", “ts", “du"是保留字段,不能作为event ID及key的名称
5. 使用分发渠道分析有时需要统计应用程序的分发渠道,例如有多少用户来从联想乐园下载了您的应用,又有多少用户通过Google android market下载到您的应用程序。您只需要在AndroidManifest.xml里添加meta-data,并将 value属性修改为对应的发布渠道名。
配置AndroidManifest.XML添加下面代码
<application ……><activity ……/><meta-dataandroid:value="Channel ID"android:name="UMENG_CHANNEL"/></application>当然,这需要您在不同渠道发布应用程序时,重新编译打包。
说明
不要改变\'UMENG_CHANNEL\',修改\'Channel ID\'为您的渠道名称,注意不能是纯数字(eg.value="AndroidMarket")。
每台设备只记录第一次统计到的渠道,您如果在测试的时候发现渠道统计到的设备数量不增加,很可能是因为您用同一个设备修改过渠道号,您换一台设备测试即可。
6. 使用在线配置功能这个功能目前可以帮你在网站上动态配置两种类型的参数:
自定义key-value型的键值对
数据发送策略
在程序的入口Activity的OnCreate()方法中调用
publicvoid onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); MobclickAgent.updateOnlineConfig(this);API:public voidupdateOnlineConfig(Context context) 参考技术A 设备mac地址
Android 友盟统计的配置及实现(事件报错统计)
记得很久以前有做过友盟这个东西,不过这个功能是同事弄的。现在在另一家公司做了,整个项目都是要通过自己开发(菜鸟级)。
最近又做了友盟这个统计的东西,有了似曾相识的感觉,还是觉得蛮好用的,文章也对友盟统计做了整理。主要写成两个工具类。这里希望对大家有所帮助,斗胆说一句,不懂可以问我,必以所知告之于你,没错就是这么热诚。
一、统计到的信息:
1、错误信息
2、新增用户、启动
3、渠道
4、事件统计
二、配置:
详细可以看官网:http://dev.umeng.com/analytics/android-doc/integration#1_2
1、在Gradle依赖中添加:
dependencies
compile 'com.umeng.analytics:analytics:latest.integration'
如果无法正常集成请添加如下代码 :
allprojects
repositories
mavenCentral()
2、manifest的配置主要包括添加权限,以下权限缺一不可,填写Appkey和填写渠道id三部分,代码示例如下:
<manifest……>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<application ……>
……
<activity ……/>
<meta-data android:value="YOUR_APP_KEY" android:name="UMENG_APPKEY"/>
<meta-data android:value="Channel ID" android:name="UMENG_CHANNEL"/>
</application>
</manifest>
andriod 6.0之后,设备信息部分获取有所变动,请参考官网:https://developer.android.com/training/permissions/requesting.html
小技巧:当xml中的targetSdkVersion=x(x<23)时候, 可以正常获取信息(相当于跳过了6.0权限检查)
上面中的Channel ID:这个渠道的一个id,默认要本身的渠道要填写
<meta-data android:value="default" android:name="UMENG_CHANNEL"/>
<meta-data android:value="...." android:name="UMENG_CHANNEL"/>
2.1 填写appkey将<meta-data android:value="YOUR_APP_KEY " android:name="UMENG_APPKEY"></meta-data> 中的YOUR_APP_KEY 替换为您在友盟后台申请的应用Appkey(Appkey可在统计后台的 统计分析->设置->应用信息 页面查看),其他部分均不需改动。2.3 channel填写将<meta-data android:value="Channel ID" android:name="UMENG_CHANNEL"/> 中的Channel ID 替换为您应用的推广渠道名称,channel id自定义。
例如在豌豆荚渠道推广此包,代码示例: <meta-data android:value="Wandoujia" android:name="UMENG_CHANNEL"/>
渠道命名规范
1.可以由英文字母、阿拉伯数字、下划线、中划线、空格、括号组成,可以含汉字以及其他明文字符,但是不建议使用中文命名,会出现乱码。
2.首尾字符不可以为空格
3.不要使用纯数字作为渠道ID
4.最多256个字符
5."unknown" 及其各种大小写形式,作为友盟保留的字段,不可以作为渠道名在您查看数据时,渠道会作为一个数据细分的维度。
三、代码实现,以下做了整理成了两个工具类:
- UmengUtils:统计配置初始化
- UmengEventUtils:事件统计(计数事件)
1、UmengUtils.class
import android.content.Context;
import com.umeng.analytics.MobclickAgent;
/**
* Created by SoBan on 2017/3/23.
* Describe: 统计配置初始化
*/
public class UmengUtils
/**
* 在Application中做的初始化
*/
public static void initUmeng()
MobclickAgent.setDebugMode(true);//开启调试模式(如果不开启debug运行不会上传umeng统计)
MobclickAgent.openActivityDurationTrack(false);
// AnalyticsConfig.setChannel(Common.getChannel());
/**
* 在BaseActivity跟BaseFragmentActivity中的onResume加入
*
* @param context
*/
public static void onResumeToActivity(Context context)
MobclickAgent.onPageStart(context.getClass().getName());
MobclickAgent.onResume(context);
/**
* 在BaseActivity跟BaseFragmentActivity中的onPause加入
*
* @param context
*/
public static void onPauseToActivity(Context context)
MobclickAgent.onPageEnd(context.getClass().getName());
MobclickAgent.onPause(context);
/**
* 在BaseFragment中的onResume加入
*
* @param context
*/
public static void onResumeToFragment(Context context)
MobclickAgent.onPageStart(context.getClass().getName());
/**
* 在BaseFragment中的onPause加入
*
* @param context
*/
public static void onPauseToFragment(Context context)
MobclickAgent.onPageEnd(context.getClass().getName());
/**
* 在登录成功的地方调用
*
* @param userId 用户id
*/
public static void onLogin(String userId)
MobclickAgent.onProfileSignIn(userId);
/**
* 在退出登录的地方调用
*/
public static void onLogout()
MobclickAgent.onProfileSignOff();
2、UmengEventUtils.class:事件统计的工具类(以我的项目为例要统计以下5点)
- 首次安装:手机型号,mac,imsi,imei
- 登录:用户userid,手机号,手机型号,mac,imsi,imei
- 退出:用户userid
- 充值:商品id, 商品名,用户userid,手机号,支付方式,支付价格
- 扫码app支付:商家id,商家名,用户userid, 手机号,支付方式,支付价格
import android.content.Context;
import com.umeng.analytics.MobclickAgent;
import org.chiki.base.utils.CommonUtils;
import java.util.HashMap;
/**
* Created by SoBan on 2017/3/23.
* Describe: 事件统计(计数事件)
*/
public class UmengEventUtils
private static final String DEVICEID = "deviceid";
private static final String IMSI = "imsi";
private static final String MAC = "mac";
private static final String PHONEMODEL = "phone_model";
private static final String USERID = "userid";
private static final String PHONE = "phone";
private static final String GOODSID = "goodsid";
private static final String GOODSNAME = "goodsname";
private static final String SHOPID = "shopid";
private static final String SHOPNAME = "shopname";
private static final String PRICE = "price";
private static final String PAYWAY = "payway";
/**
* 首次安装
*
* @param ctx
*/
public static void toInstallClick(Context ctx)
HashMap<String, String> map = getInstallMap(ctx);
MobclickAgent.onEvent(ctx, "install", map);
/**
* 登录
*
* @param ctx
* @param userId
* @param phone
*/
public static void toLoginClick(Context ctx, String userId, String phone)
HashMap<String, String> map = getInstallMap(ctx);
map.put(USERID, userId);
map.put(PHONE, phone);
MobclickAgent.onEvent(ctx, "login", map);
/**
* 退出
*
* @param ctx
* @param userId
*/
public static void toLogoutClick(Context ctx, String userId)
HashMap<String, String> map = getInstallMap(ctx);
map.put(USERID, userId);
MobclickAgent.onEvent(ctx, "logout", map);
/**
* 充值
*
* @param ctx
* @param userId
* @param goodsId
* @param goodsName
* @param price
* @param payway
*/
public static void toRechargeClick(Context ctx, String userId, String phone,
String goodsId, String goodsName, int price, String payway)
HashMap<String, String> map = new HashMap<String, String>();
map.put(USERID, userId);
map.put(PHONE, phone);
map.put(GOODSID, goodsId);
map.put(GOODSNAME, goodsName);
map.put(PRICE, String.valueOf(price));
map.put(PAYWAY, payway);
MobclickAgent.onEvent(ctx, "recharge", map);
/**
* 扫码app支付
*
* @param ctx
* @param userId
* @param phone
* @param shopId
* @param shopName
* @param price
* @param payway
*/
public static void toSweepPaymentClick(Context ctx, String userId, String phone,
String shopId, String shopName, int price, String payway)
HashMap<String, String> map = new HashMap<String, String>();
map.put(USERID, userId);
map.put(PHONE, phone);
map.put(SHOPID, shopId);
map.put(SHOPNAME, shopName);
map.put(PRICE, String.valueOf(price));
map.put(PAYWAY, payway);
MobclickAgent.onEvent(ctx, "sweeppayment", map);
private static HashMap<String, String> getInstallMap(Context ctx)
HashMap<String, String> map = new HashMap<String, String>();
map.put(PHONEMODEL, CommonUtils.getPhoneModel());
map.put(DEVICEID, CommonUtils.getDeviceId(ctx));
map.put(IMSI, CommonUtils.getIMSI(ctx));
map.put(MAC, CommonUtils.getLocalMacAddressFromWifiInfo(ctx));
return map;
3、CommonUtils.class:获取系统信息类
public class CommonUtils
/**
* 获取版本号(内部识别号) = 101
*
* @param context
* @return
*/
public static int getVersionCode(Context context)
try
PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
return pi.versionCode;
catch (PackageManager.NameNotFoundException e)
// TODO Auto-generated catch block
e.printStackTrace();
return 0;
/**
* 获取版本号 = "1.0.1";
*
* @param context
* @return
*/
public static String getVersionName(Context context)
try
PackageInfo pi = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
return pi.versionName;
catch (PackageManager.NameNotFoundException e)
// TODO Auto-generated catch block
e.printStackTrace();
return "未知版本";
/**
* 获取IMEI标识(手机唯一的标识)
*
* @param context
* @return
*/
public static String getDeviceId(Context context)
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
String device_id = tm.getDeviceId();
//如果Android Pad没有IMEI,用此方法获取设备ANDROID_ID
if (TextUtils.isEmpty(device_id))
device_id = android.provider.Settings.Secure.getString(context.getContentResolver(),
android.provider.Settings.Secure.ANDROID_ID);
return device_id;
/**
* 获取运营商sim卡imsi号
*
* @return
*/
public static String getIMSI(Context context)
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
String android_imsi = tm.getSubscriberId();
return android_imsi;
/**
* 根据Wifi信息获取本地Mac
*
* @param context
* @return
*/
public static String getLocalMacAddressFromWifiInfo(Context context)
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo info = wifi.getConnectionInfo();
return info.getMacAddress();
/**
* 获取ip地址
*
* @return
*/
public static String getHostIP()
String hostIp = "";
try
Enumeration nis = NetworkInterface.getNetworkInterfaces();
InetAddress ia = null;
while (nis.hasMoreElements())
NetworkInterface ni = (NetworkInterface) nis.nextElement();
Enumeration<InetAddress> ias = ni.getInetAddresses();
while (ias.hasMoreElements())
ia = ias.nextElement();
if (ia instanceof Inet6Address)
continue;// skip ipv6
String ip = ia.getHostAddress();
if (!"127.0.0.1".equals(ip))
hostIp = ia.getHostAddress();
break;
catch (SocketException e)
Log.i("yao", "SocketException");
e.printStackTrace();
return hostIp;
/**
* 获取手机型号
*
* @return
*/
public static String getPhoneModel()
String model = Build.MODEL;
if (TextUtils.isEmpty(model))
return "";
return model;
/**
* 获取手机系统版本号
*
* @return
*/
public static String getVersionRelease()
String version = Build.VERSION.RELEASE;
if (TextUtils.isEmpty(version))
return "";
return version;
四、这些配置跟代码都实现了,之后现在就是要来看看平台上的数据是否有咯,对吧!各位应该都是这么想的,那就对了,跟我一开始是一样的。不过在平台上,如果你还是没有看到统计的信息的话,个人觉得有以下几点:
1、MobclickAgent.setDebugMode(true);//开启调试模式(如果不开启debug运行不会上传umeng统计)2、查看是不是配置是否正确
3、平台上的设置-->使用账号统计报表-->启动使用
4、若有事件管理处重置某个事件,那么这个事件要在次日在起作用
五、效果展示:
这里有必要说说图一:这个是事件统计的事件管理,点击事件id就可以看到里面的很多之前设置的事件要统计的userid,设备等等,具体可以看图二效果
以上是关于友盟统计怎么算新增用户 android的主要内容,如果未能解决你的问题,请参考以下文章