利用信鴿推送實現Android登錄後強制退出的功能(單點登錄)

首先整理思路,先思考實現邏輯:
1.集成信鴿推送
2.實現自定義推送
3.在自定義推送中,接收推送的方法內啓動強制退出功能。

思路邏輯很簡單,但是實現起來就得一步一步做,先集成信鴿:
這裏主要是參考官方開發文檔即可
然後是實現自定義推送接受方,即自定義receiver

CustomReceiver.java

/**
 * 
 */
import u.upd.l;
import android.content.Context;
import android.content.Intent;
import com.dhcc.gpscarmanager_phone.CustomServices.ForceOfflineService;
import com.dhcc.gpscarmanager_phone.Util.L;
import com.tencent.android.tpush.XGPushBaseReceiver;
import com.tencent.android.tpush.XGPushClickedResult;
import com.tencent.android.tpush.XGPushRegisterResult;
import com.tencent.android.tpush.XGPushShowedResult;
import com.tencent.android.tpush.XGPushTextMessage;

public class CustomReceiver extends XGPushBaseReceiver {
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.tencent.android.tpush.XGPushBaseReceiver#onDeleteTagResult(android
	 * .content.Context, int, java.lang.String)
	 */
	@Override
	public void onDeleteTagResult(Context context, int arg1, String arg2) {
		// TODO Auto-generated method stub
	}
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.tencent.android.tpush.XGPushBaseReceiver#onNotifactionClickedResult
	 * (android.content.Context, com.tencent.android.tpush.XGPushClickedResult)
	 */
	@Override
	public void onNotifactionClickedResult(Context context,
			XGPushClickedResult arg1) {
		// TODO Auto-generated method stub
	}
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.tencent.android.tpush.XGPushBaseReceiver#onNotifactionShowedResult
	 * (android.content.Context, com.tencent.android.tpush.XGPushShowedResult)
	 */
	@Override
	public void onNotifactionShowedResult(Context context,
			XGPushShowedResult result) {
		// TODO Auto-generated method stub
		// 這裏是測試代碼,在接受到“下線”這兩個字後,接收通知的應用強行下線
		if ("下線".equals(result.getContent())) {
			L.e(result.getContent());
			context.getApplicationContext().startService(new Intent(context.getApplicationContext(), ForceOfflineService.class));
		}
	}
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.tencent.android.tpush.XGPushBaseReceiver#onRegisterResult(android
	 * .content.Context, int, com.tencent.android.tpush.XGPushRegisterResult)
	 */
	@Override
	public void onRegisterResult(Context context, int arg1,
			XGPushRegisterResult arg2) {
		// TODO Auto-generated method stub
	}
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.tencent.android.tpush.XGPushBaseReceiver#onSetTagResult(android.content
	 * .Context, int, java.lang.String)
	 */
	@Override
	public void onSetTagResult(Context context, int arg1, String arg2) {
		// TODO Auto-generated method stub
	}
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.tencent.android.tpush.XGPushBaseReceiver#onTextMessage(android.content
	 * .Context, com.tencent.android.tpush.XGPushTextMessage)
	 */
	@Override
	public void onTextMessage(Context context, XGPushTextMessage message) {
		// TODO Auto-generated method stub
	}
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.tencent.android.tpush.XGPushBaseReceiver#onUnregisterResult(android
	 * .content.Context, int)
	 */
	@Override
	public void onUnregisterResult(Context context, int arg1) {
		// TODO Auto-generated method stub
	}
}


在註冊文件中加入該Revceiver的靜態註冊代碼:

<receiver android:name="CustomReceivers.CustomReceiver" >
            <intent-filter>
                <!-- 接收消息透傳 -->
                <action android:name="com.tencent.android.tpush.action.PUSH_MESSAGE" />
                <!-- 監聽註冊、反註冊、設置/刪除標籤、通知被點擊等處理結果 -->
                <action android:name="com.tencent.android.tpush.action.FEEDBACK" />
            </intent-filter>
        </receiver>

然後注意這句代碼:

if ("下線".equals(result.getContent())) {
			L.e(result.getContent());
			context.getApplicationContext().startService(new Intent(context.getApplicationContext(), ForceOfflineService.class));
		}
由於目前是測試代碼,所以我判斷的是如果服務端發送的是“下線”的話,我就將該設備強制下線,在實際開發的過程中,其流程應當是

用戶登錄-> 判斷當前的Token與數據庫中存儲的Token是否一致-> 如果不一致,則對數據庫中的Token的用戶發送約定好的下線通知,可以是參數也可以是字符串-> 手機端接到下線通知後,強制下線-> 服務端將新的Token保存到數據庫中去,老的Token銷燬


然後可以注意到,這裏是啓動了一個Service,然後利用Service進行下線操作的:

/**
 * 
 */
import com.dhcc.gpscarmanager_phone.CustomReceivers.ForceOfflineReceiver;
import com.dhcc.gpscarmanager_phone.Util.L;
import u.upd.l;
import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.util.Log;

public class ForceOfflineService extends Service {
	private static final String TAG = "ForceOfflineService";   
	ForceOfflineReceiver forceOfflineReceiver;
    @Override  
    public void onCreate() {  
        Log.i(TAG, "ExampleService-onCreate");  
        super.onCreate();  
       
        IntentFilter intentFilter=new IntentFilter();
        intentFilter.addAction("com.dhcc.AppOffline");
         forceOfflineReceiver=new ForceOfflineReceiver();
        registerReceiver(forceOfflineReceiver, intentFilter);
        
        Intent intent =new Intent("com.dhcc.AppOffline");
        getApplicationContext().sendBroadcast(intent);
    }  
  
    @Override  
    public void onStart(Intent intent, int startId) {  
        Log.i(TAG, "ExampleService-onStart");  
        super.onStart(intent, startId);  
    }  
  
    @Override  
    public int onStartCommand(Intent intent, int flags, int startId) {  
        //執行文件的下載或者播放等操作  
        Log.i(TAG, "ExampleService-onStartCommand");  
        /*  
         * 這裏返回狀態有三個值,分別是:  
         * 1、START_STICKY:當服務進程在運行時被殺死,系統將會把它置爲started狀態,但是不保存其傳遞的Intent對象,之後,系統會嘗試重新創建服務;  
         * 2、START_NOT_STICKY:當服務進程在運行時被殺死,並且沒有新的Intent對象傳遞過來的話,系統將會把它置爲started狀態,  
         *   但是系統不會重新創建服務,直到startService(Intent intent)方法再次被調用;  
         * 3、START_REDELIVER_INTENT:當服務進程在運行時被殺死,它將會在隔一段時間後自動創建,並且最後一個傳遞的Intent對象將會再次傳遞過來。  
         */  
        return super.onStartCommand(intent, flags, startId);  
    }  
  
    @Override  
    public IBinder onBind(Intent intent) {  
        Log.i(TAG, "ExampleService-onBind");  
        return null;  
    }  
      
    @Override  
    public void onDestroy() {  
        Log.i(TAG, "ExampleService-onDestroy");  
        super.onDestroy();  
        unregisterReceiver(forceOfflineReceiver);
    }  
  
}

別忘了在配置文件中加入Service的註冊:

<!-- 強制下線服務 -->
		<service android:name="com.dhcc.gpscarmanager_phone.CustomServices.ForceOfflineService"/>
在OnCreate方法中加入了啓動強制下線的Receiver的代碼:

IntentFilter intentFilter = new IntentFilter();
		intentFilter.addAction("com.dhcc.AppOffline");
		forceOfflineReceiver = new ForceOfflineReceiver();
		registerReceiver(forceOfflineReceiver, intentFilter);
		Intent intent = new Intent("com.dhcc.AppOffline");
		getApplicationContext().sendBroadcast(intent);

這裏要注意的是,不能直接用Context進行啓動下線Receiver的操作,否則會報錯:

IntentReceiver components are not allowed to register to receive intents

必須利用getApplicationContext的方式動態註冊ForceOfflineRecevier(),不能用靜態註冊的方式,否則也會報上邊同樣的錯誤(但是這裏不知道爲什麼)
具體解決原因參照:http://blog.csdn.net/eimsteim/article/details/7220920
然後啓動這個ForceOfflineReceiver,他的內容是這樣的:
import com.baidu.navisdk.util.common.Stopwatch;
import com.dhcc.gpscarmanager_phone.CustomServices.ForceOfflineService;
import com.dhcc.gpscarmanager_phone.CustomView.ActivityCollector;
import com.dhcc.gpscarmanager_phone.Module.Welcome.WelcomPage.LoginActivity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.view.WindowManager;

public class ForceOfflineReceiver extends BroadcastReceiver {
	/*
	 * (non-Javadoc)
	 * 
	 * @see android.content.BroadcastReceiver#onReceive(android.content.Context,
	 * android.content.Intent)
	 */
	@Override
	public void onReceive(final Context context, Intent intent) {
		// TODO Auto-generated method stub
		intent = new Intent(context, ForceOfflineService.class);  
		context.stopService(intent);
		AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
		dialogBuilder.setTitle("已下線");
		dialogBuilder.setMessage("您的賬戶已在另一個設備登錄,請嘗試重新登陸");
		dialogBuilder.setCancelable(false);
		dialogBuilder.setPositiveButton("登   錄", new OnClickListener() {
			@Override
			public void onClick(DialogInterface arg0, int arg1) {
				// TODO Auto-generated method stub
				ActivityCollector.finishAll();
				Intent intent = new Intent(context, LoginActivity.class);
				intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				context.startActivity(intent);
			}
		});
		AlertDialog alertDialog = dialogBuilder.create();
		alertDialog.getWindow().setType(
				WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
		alertDialog.show();
	}
}

啓動一個窗口,告訴用戶你的賬戶在其他設備登錄了,然後強制啓動登錄界面,並把之前啓動的Activity都關閉掉,所以這裏的關鍵類就是
ActivityCollector了:

import java.util.ArrayList;
import java.util.List;
import android.app.Activity;

public class ActivityCollector {
	
	public static List<Activity> activities=new ArrayList<Activity>();
	
	public static void addActivity(Activity activity){
		
		activities.add(activity);
		
	}
	
	public static void removeActivity(Activity activity){
		
		activities.remove(activity);
		
	}
	
	public static void finishAll(){
		
		for(Activity activity:activities){
			
			if(activity.isFinishing()){
				
				activity.finish();
			}
		}
		
	}
}

功能自己看,然後就是在你的基類BaseActivity里加入對應的代碼:

@Override
	public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
		ActivityCollector.addActivity(this);
}
protected void onDestroy(){
		
		super.onDestroy();
		ActivityCollector.removeActivity(this);
		
	}

這樣就把新啓動的Activity管理起來了,然後在關閉的時候利用循環關閉對應的Activity即可了。
由於使用的是系統的彈出窗口,所以要在配置文件中加入這麼一句權限:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章