PhoneGap управление redirect

Автор: Eugeniy Marilev
Дата публикации: 2014-05-06 10:27:57

«Кто бы мог подумать, уму непостижимо» - моя первая фраза, которую произнес после того как узнал, что PhoneGap осуществляя любой redirect, за исключением стартового домена, открывает ссылку в стандартном браузере... Перепробовал разные варианты:

location = "some.domail.com";
window.location = "some.domail.com";
window.location.href = "some.domail.com";

Увы, все оказалось бессмысленным, т.к. предполагал, что нужно его делать как-то по особому, не так как обычно в javascript. Оказывается, что суть проблемы заключается в том, что PhoneGap не доверяет сторонним доменам. Понадобиться данная защита может в следующей ситуации - при размещении пользователями системы в комментариях ссылок на свои ресурсы. Логично же, чтобы сторонние ссылки не открывались внутри окна текущего приложения, иначе у пользователя создается впечатление, что он работает не с native-приложением, а с обычным браузером. Но сложившаяся у меня ситуация никак по подпадала под вышеописанный случай. Мне нужно было сделать аутентификацию приложения с помощью Facebook oAuth. При этом было вполне логично, что приложение делало бы redirect на форму авторизации facebook, затем еще пару переадресаций... и в результате попадало на главную страницу приложения. Позже, конечно, вариант аутентификации с redirect'ами в главном окне приложения был успешно заменен использованием аналогичного механизма, но внутри всплывающего диалога PhoneGap.

В новейших версиях PhoneGap, собственно полное внедрение данного механизма будет в далеком будущем, появился вариант решения данной проблемы — While list. На сколько известно мне, работает данное решение только в IOS и Windows Phone 7. Поэтому, можно смело забить на присутствие подобного функционала, ибо главная проблема — проблема кроссплатформенности — не будет решена. Кому интересно попробовать White list — читаем здесь. Предлагаю использовать альтернативный подход, который, определенно, гораздо гибче предоставляемого стандартного. Для переопределения стандартного механизма обработки redirect'ов для нашего приложения нам нужно будет перегрузить метод shouldOverrideUrlLoading - для Android, shouldStartLoadWithRequest — для IPhone. Решение для Windows Phone - найдете сами, домашнее задание :). А вот и примеры:

Управление redirect'ом Android

package com.myapp;

import java.net.MalformedURLException;

import com.phonegap.*;
import android.webkit.*;

public class MyDroidGap extends DroidGap
{
    /**
     * Create and initialize web container.
     */
    public void init()
    {
        super.init();
        this.setWebViewClient(this.appView, new My GapViewClient(this));
    }

    /**
     * The webview client receives notifications about appView
     */
    public class MyGapViewClient extends GapViewClient
    {
    	/**
    	 * Application's URL loading schema 
    	 */
    	final UrlLoadingSchema urlSchema;
    	
        /**
         * Constructor.
         * 
         * @param ctx
         */
        public MyGapViewClient(DroidGap ctx)
        {
            super(ctx);
            urlSchema = new UrlLoadingSchema();
        }
        
        /**
         * Give the host application a chance to take over the control when a new url 
         * is about to be loaded in the current WebView.
         * 
         * @param view          The WebView that is initiating the callback.
         * @param url           The url to be loaded.
         * @return              true to override, false for default behavior
         */
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url)
        {
             try {
	         if (this.urlSchema.isInternalUrl(url)) {
		     view.loadUrl(url);
		     return true;
		 } else {
		     return super.shouldOverrideUrlLoading(view, url);
		 }
             } catch (MalformedURLException e) {
		 e.printStackTrace();
	     } catch (Exception e) {
		 e.printStackTrace();
	     }
	     return super.shouldOverrideUrlLoading(view, url);
        }
    }
}

После чего нужно будет главную активность приложения отнаследовать от класса MyGroidGap.

Управление redirect'ом IPhone

//
//  AppDelegate.m
//  My application
//
//  Created by Evgeniy Marilev on 10.09.11.
//  Copyright __MyCompanyName__ 2011. All rights reserved.
//

#import "AppDelegate.h"
#ifdef PHONEGAP_FRAMEWORK
	#import 
#else
	#import "PhoneGapViewController.h"
#endif

#import "UrlLoadingSchema.h"

@implementation AppDelegate

@synthesize invokeString;
@synthesize loadingSchema;

- (id) init
{
    self.loadingSchema = [[UrlLoadingSchema alloc] init];
    return [super init];
}

//.....

/**
 * Start Loading Request
 * This is where most of the magic happens... We take the request(s) and process the response.
 * From here we can re direct links and other protocalls to different internal methods.
 */
- (BOOL)webView:(UIWebView *)theWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSURL *url = [request URL];
    if ([self.loadingSchema isInternalUrl: url]) {
        return YES;
    } else {
        return [ super webView:theWebView shouldStartLoadWithRequest:request navigationType:navigationType ];
    }
}

//.....

- (void)dealloc
{
	[loadingSchema release];
	[ super dealloc ];
}

@end

В целом об оформлении политики redirect

В вышеописанных примерах фигурирует некий класс «UrlLoadingSchema». Если вы подумали, что это какой-то стандартный класс — вы ошиблись. «UrlLoadingSchema» - самый обычный класс с одним public-методом «isInternalUrl». Использование именно такого названия, да и, вообще, в данной ситуации специального класса может показаться ненужным — это просто мой совет... А как реализовывать переопределение — решать вам. Главное, чтобы переопределяемые методы возвращали TRUE, когда адрес можно загрузить в главном webView приложения, а иначе — вернуть FALSE. Можно пойти дальше, и определить механизм White list основываясь на переопределении вышеприведенных методов, и не обрабатывать запретный URL ни при каких ситуациях, а просто выдавать сообщение об ошибке. Вывод из раскрытого материала данной статьи — не всегда, но бывает так, что даже отлично спроектированная система не предоставляет готового решения ваших проблемных ситуаций, в таком случае нужно запастись терпением, вооружиться google и исходниками, и в нужно месте вставить нужные вам «пару строк кода», и можно двигаться дальше...

Комментарии к статье
Комментарии:
Александр
20\03\2012
Прошу прощения за некоторую неграмотность, но, можно показать на конкретном примере как это реализовать? Куда прописывается super.loadUrl("file:///android_asset/www/myLocalFile.html"); и как в приложении переходить по ссылкам ?
djvibegga_admin
25\03\2012
Вызов
super.loadUrl(«file:///android_asset/www/myLocalFile.html»
нужно выполнять в главной activity (активности) приложения. Подробный пример описан на официальном сайте phonegap. Вариант для android смотри здесь.
Только зарегистрированые пользователи могут оставлять комментарии