Pull to refresh

Добавляем запись на стену Вконтакте из Android-приложения

Reading time5 min
Views22K
Всем снова привет! Я вернулся.

Уже несколько человек ждет пост о публикации записей на свою стену вконтакте. И вот эта статья. В ней будет много кода, теории вообще не будет, потому что все довольно просто и тем не менее данный пост может быть полезен тем, кто ломает голову о том как решить данную задачу.

Поехали.


Предистория


Прежде всего искал доступные варианты. Их не оказалось, поэтому обратил внимание на готовые решения для твиттера и фэйсбук и на примере последнего написал несколько классов для Вконтакте.
Идея данного примера взята из Facebook SDK, доступного по адресу: Facebook SDK

Как это работает?


Проект(звучит сильно конечно, ок… проектик) состоит из трех классов(ссылка на репу в конце статьи): VkSession — класс сохранения/получения параметров вконтакте(токен, user_id и т.д.), VkDialog — класс пользовательского диалога, VkApp — класс, объединяющий в себе все классы и выполняющий основную работу.

На самом деле тут и описывать то нечего. У Вконтакте есть документация по API — Дока по API. Находим функцию wall.post — Тыц. Читаем и разбираемся.

Важно понять принципы работы OAuth. В данном случае нужно получить идентификатор приложения(есть соответствующая форма) и далее работать с API, передавая данный ID. При работе с API Вконтакте будет посылать нам AccessToken, который нужно сохранять. Данный токен живет всего 24 часа, поэтому его необходимо проверять и сохранять время получения токена. Данные параметры я объединил в класс VkSession:

package vkontakte;

import android.content.Context;
import android.content.SharedPreferences;

public class VkSession {
    private SharedPreferences _prefs;
    private final String PREFS_NAME = "Vk:Settings";
    private Context _context;
    private SharedPreferences.Editor _editor;
    
    public VkSession(){}
    
    public VkSession(Context context){
    	_context = context;
    	_prefs = _context.getSharedPreferences(PREFS_NAME, 0);
        _editor = _prefs.edit();
    }
    
    public void saveAccessToken(String accessToken, String expires, String userId){
    	_editor.putString("VkAccessToken", accessToken);
    	_editor.putString("VkExpiresIn", expires);
    	_editor.putString("VkUserId", userId);
    	_editor.putLong("VkAccessTime", System.currentTimeMillis());
    	_editor.commit();
    }
    
    public String[] getAccessToken(){
    	String[] params = new String[4];
    	params[0] = _prefs.getString("VkAccessToken", "");
    	params[1] = _prefs.getString("VkExpiresIn", "");
    	params[2] = _prefs.getString("VkUserId", "");
    	params[3] =  String.valueOf(_prefs.getLong("VkAccessTime",0));
    	return params;
    }
    
    public void resetAccessToken(){
    	_editor.putString("VkAccessToken", "");
    	_editor.putString("VkExpiresIn", "");
    	_editor.putString("VkUserId", "");
    	_editor.putLong("VkAccessTime", 0);
    	_editor.commit();
    }   
}


Как видите, ничего сложного. Полученные настройки сохраняем в SharedPreferences. Ну и все.

Далее, самое интересное. Класс VkApp, а точнее наиболее интересные его части с пояснениями:

public class VkApp {
        //constants for OAUTH AUTHORIZE in Vkontakte
	public static final String CALLBACK_URL = "http://api.vkontakte.ru/blank.html";
	private static final String OAUTH_AUTHORIZE_URL = "http://api.vkontakte.ru/oauth/authorize?client_id=2020214&scope=8192&redirect_uri=http://api.vkontakte.ru/blank.html&display=touch&response_type=token"; 
		 
	private Context _context;
	private VkDialogListener _listener;
	private VkSession _vkSess;
	
	private String VK_API_URL = "https://api.vkontakte.ru/method/";
	private String VK_POST_TO_WALL_URL = VK_API_URL + "wall.post?";
        ...

Поясняю. Когда мы посылаем запрос, вконтакте отправляет ответ и ридеректит нас на адрес api.vkontakte.ru/blank.html, по суте это пустая страница(точную суть работы уже не припомню, писал код давно, так что имейте ввиду). Важно перехватывать данный адрес и реагировать на него нужным образом. Далее, идет собственно строка запроса со всеми нужными параметрами: наш идентификатор, scope(права доступа), тип дисплея, адрес ридеректа, вообщем все это есть в доке. Читайте!

Продолжаем:
      //parse vkontakte JSON response
       private boolean parseResponse(String jsonStr){
		boolean errorFlag = true;
		
		JSONObject jsonObj = null;
		try {
		   jsonObj = new JSONObject(jsonStr);
		   JSONObject errorObj = null;
		   
		   if( jsonObj.has("error") ) {
		       errorObj = jsonObj.getJSONObject("error");
		       int errCode = errorObj.getInt("error_code");
		       if( errCode == 14){
		    	   errorFlag = false;
		       }
		   }
		}
		catch (JSONException e) {
			e.printStackTrace();
		}
		
		return errorFlag;	
	}
	
	//publicate message to vk users' wall 
	public boolean postToWall(String message) {
                boolean errorFlag = true;
		String[] params = _vkSess.getAccessToken();
		
		String accessToken = params[0];
		String ownerId = params[2];
		
	        //set request uri params
		VK_POST_TO_WALL_URL += "owner_id="+ownerId+"&message="+Uri.encode(message)+"&access_token="+accessToken;
		
		//send request to vkontakte api
		HttpClient client = new DefaultHttpClient();
                HttpGet request = new HttpGet(VK_POST_TO_WALL_URL);
        
                try {
                     HttpResponse response = client.execute(request);
                     HttpEntity entity = response.getEntity();

                     String responseText = EntityUtils.toString(entity);
            
                     //parse response for error code or not
                     errorFlag = parseResponse(responseText);
               }
               catch(ClientProtocolException cexc){
        	   cexc.printStackTrace();
               }
               catch(IOException ioex){
        	    ioex.printStackTrace();
               }
        
               return errorFlag;
	}

В Андроид есть удобный набор классов от Apache для выполнения запросов, получения, разбор ответом и т.д. — HttpClient. В данном случае мы формируем GET-запрос и далее получаем ответ.

Диалог состоит из WebView и для него переопределяется клиент:

private class VkWebViewClient extends WebViewClient { 
    	@Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
        	if (url.startsWith(VkApp.CALLBACK_URL) & ( !url.contains("error") )) {
        		mListener.onComplete(url);
        		VkDialog.this.dismiss();
        		return true;
        	} 
        	else if(url.contains("error")){
        		VkDialog.this.dismiss();
        		return false;
        	}
        	else {
        	    view.loadUrl(url);
        	    return true;
        	}
        }
    	
    	@Override
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            super.onReceivedError(view, errorCode, description, failingUrl);
            mListener.onError(description);
            VkDialog.this.dismiss();
        }
    	
    	@Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            
            if( url.contains("error") ) {
            	VkDialog.this.dismiss();
            	return;
            }
            else if( url.contains("access_token")) {
            	VkDialog.this.dismiss();
            	mListener.onComplete(url);
            	return;
            }
            mSpinner.show();
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);      
            mSpinner.dismiss();
        }
    }

В коде клиента мы ловим посылаемые адреса от вконтакте к приложению и реагируем нужным образом. Все также просто. Конечно данный код стоит доработать и не следует смело его копировать не разобравшись. Что-то поменяется на сервере и приложение будет реагировать неправильно. Кстати, в добавлении скажу, что Facebook SDK тоже сыпется, на телефонах HTC чаще всего.

Надеюсь кому-то данная статейка будет полезной!

Как обычно, интересные предложения, замечания и прочее пишем в личку.

Код доступен здесь — репа
Tags:
Hubs:
Total votes 25: ↑18 and ↓7+11
Comments8

Articles