반응형

cocos2d-x를 이용하여 Youtube동영상을 재생하는 웹화면을 개발 중인데 

cocos2d-x 3.3 이상부터 Webview를 지원하여 걱정없이 개발 하고 있었습니다.


개발 다 끝내고 iOS테스트 완료 하였습니다.. 

Android 테스트하는데... 좌절하고 말았습니다.


3가지 문제가 발생했습니다.


  1. 유투브 동영상 전체화면을 지원불가.
  2. 동영상 전체화면까지 수정했으나 전체화면에서 가로/세로 화면전환 불가.
  3. Webview를 remove하여도 동영상 사운드 계속 재생.

어찌어찌 짧은 Java실력으로 cocos2dx Java Source 수정하여 3가지 모두 해결보았습니다.

1, 2번 문제 부터 해결해 보도록 하겠습니다. 


cocos2d에 아래 경로로 가시면 Cocos2dxWebView.java 파일이 있습니다.

"프로젝트명"/cocos2d/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxWebView.java

이 파일을 아래의 소스로 교체 합니다.


[ Cocos2dxWebView.java File ]


package org.cocos2dx.lib;

 

import android.annotation.SuppressLint;

import android.app.Activity;

import android.app.ProgressDialog;

import android.content.Context;

import android.content.pm.ActivityInfo;

import android.graphics.Bitmap;

import android.os.Build;

import android.util.Log;

import android.view.Gravity;

import android.view.MotionEvent;

import android.view.View;

import android.view.ViewGroup;

import android.view.Window;

import android.view.WindowManager;

import android.webkit.JsResult;

import android.webkit.WebChromeClient;

import android.webkit.WebSettings;

import android.webkit.WebView;

import android.webkit.WebViewClient;

import android.widget.FrameLayout;

import android.widget.Toast;

 

import java.lang.reflect.Method;

import java.net.URI;

import java.util.concurrent.CountDownLatch;

 

class ShouldStartLoadingWorker implements Runnable {

    private CountDownLatch mLatch;

    private boolean[] mResult;

    private final int mViewTag;

    private final String mUrlString;

    

    ShouldStartLoadingWorker(CountDownLatch latch, boolean[] result, int viewTag, String urlString) {

        this.mLatch = latch;

        this.mResult = result;

        this.mViewTag = viewTag;

        this.mUrlString = urlString;

    }

    

    @Override

    public void run() {

        this.mResult[0] = Cocos2dxWebViewHelper._shouldStartLoading(mViewTag, mUrlString);

        this.mLatch.countDown(); // notify that result is ready

    }

}

 

public class Cocos2dxWebView extends WebView {

    private static final String TAG = Cocos2dxWebViewHelper.class.getSimpleName();

    

    private int mViewTag;

    private String mJSScheme;

    

    public Cocos2dxWebView(Context context) {

        this(context, -1);

    }

    

    @SuppressLint("SetJavaScriptEnabled")

    public Cocos2dxWebView(Context context, int viewTag) {

        super(context);

        this.mViewTag = viewTag;

        this.mJSScheme = "";

        

        this.setFocusable(true);

        this.setFocusableInTouchMode(true);

        

        this.getSettings().setSupportZoom(false);

        this.getSettings().setJavaScriptEnabled(true);

        this.getSettings().setDisplayZoomControls(true);

        

        // `searchBoxJavaBridge_` has big security risk. http://jvn.jp/en/jp/JVN53768697

        try {

            Method method = this.getClass().getMethod("removeJavascriptInterface", new Class[]{String.class});

            method.invoke(this, "searchBoxJavaBridge_");

        } catch (Exception e) {

            Log.d(TAG, "This API level do not support `removeJavascriptInterface`");

        }

        

        this.setWebViewClient(new Cocos2dxWebViewClient());

        //this.setWebChromeClient(new WebChromeClient());

 

        // 새로만든 Chromeclient를 추가.

        this.setWebChromeClient(new ChromeClient((Cocos2dxActivity)getContext()));

    }

    

    public void setJavascriptInterfaceScheme(String scheme) {

        this.mJSScheme = scheme != null ? scheme : "";

    }

    

    public void setScalesPageToFit(boolean scalesPageToFit) {

        this.getSettings().setSupportZoom(scalesPageToFit);

    }

    

    class Cocos2dxWebViewClient extends WebViewClient {

        @Override

        public boolean shouldOverrideUrlLoading(WebView view, final String urlString) {

            Cocos2dxActivity activity = (Cocos2dxActivity)getContext();

            

            try {

                URI uri = URI.create(urlString);

                if (uri != null && uri.getScheme().equals(mJSScheme)) {

                    activity.runOnGLThread(new Runnable() {

                        @Override

                        public void run() {

                            Cocos2dxWebViewHelper._onJsCallback(mViewTag, urlString);

                        }

                    });

                    return true;

                }

            } catch (Exception e) {

                Log.d(TAG, "Failed to create URI from url");

            }

            

            boolean[] result = new boolean[] { true };

            CountDownLatch latch = new CountDownLatch(1);

            

            // run worker on cocos thread

            activity.runOnGLThread(new ShouldStartLoadingWorker(latch, result, mViewTag, urlString));

            

            // wait for result from cocos thread

            try {

                latch.await();

            } catch (InterruptedException ex) {

                Log.d(TAG, "'shouldOverrideUrlLoading' failed");

            }

            

            return result[0];

        }

        

        @Override

        public void onPageFinished(WebView view, final String url) {

            super.onPageFinished(view, url);

            Cocos2dxActivity activity = (Cocos2dxActivity)getContext();

            activity.runOnGLThread(new Runnable() {

                @Override

                public void run() {

                    Cocos2dxWebViewHelper._didFinishLoading(mViewTag, url);

                }

            });

        }

        

        @Override

        public void onReceivedError(WebView view, int errorCode, String description, final String failingUrl) {

            super.onReceivedError(view, errorCode, description, failingUrl);

            Cocos2dxActivity activity = (Cocos2dxActivity) getContext();

            activity.runOnGLThread(new Runnable() {

                @Override

                public void run() {

                    Cocos2dxWebViewHelper._didFailLoading(mViewTag, failingUrl);

                }

            });

        }

    }

    

    public void setWebViewRect(int left, int top, int maxWidth, int maxHeight) {

        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,

                                                                             FrameLayout.LayoutParams.WRAP_CONTENT);

        layoutParams.leftMargin = left;

        layoutParams.topMargin = top;

        layoutParams.width = maxWidth;

        layoutParams.height = maxHeight;

        layoutParams.gravity = Gravity.TOP | Gravity.LEFT;

        

        this.setLayoutParams(layoutParams);

    }

    

    // 전체화면 가능한 ChromeClient를 WebVhromeClient를 상속받아 새로 만듬...

    public final class ChromeClient extends WebChromeClient {

        private View mCustomView;

        private Activity mActivity;

        

        public ChromeClient(Activity activity) {

            this.mActivity = activity;

        }

        

        @Override

        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {

            result.confirm();

            return super.onJsAlert(view, url, message, result);

        }

        

        private int mOriginalOrientation;

        private FullscreenHolder mFullscreenContainer;

        private CustomViewCallback mCustomViewCollback;

        

        @Override

        public void onShowCustomView(View view, CustomViewCallback callback) {

            

            if (mCustomView != null) {

                callback.onCustomViewHidden();

                return;

            }

            

            mOriginalOrientation = mActivity.getRequestedOrientation();

            

            FrameLayout decor = (FrameLayout) mActivity.getWindow().getDecorView();

            

            mFullscreenContainer = new FullscreenHolder(mActivity);

            mFullscreenContainer.addView(view, ViewGroup.LayoutParams.MATCH_PARENT);

            decor.addView(mFullscreenContainer, ViewGroup.LayoutParams.MATCH_PARENT);

            mCustomView = view;

            mCustomViewCollback = callback;

            //mActivity.setRequestedOrientation(mOriginalOrientation);

            

            // 기존의 프로젝트의 Orientation을 따르는 것이 아니라 전체화면일 경우는 Sensor의 의해 Orientation결정

            mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);

        }

        

        @Override

        public void onHideCustomView() {

            if (mCustomView == null) {

                return;

            }

            

            FrameLayout decor = (FrameLayout) mActivity.getWindow().getDecorView();

            decor.removeView(mFullscreenContainer);

            mFullscreenContainer = null;

            mCustomView = null;

            mCustomViewCollback.onCustomViewHidden();

            

            mActivity.setRequestedOrientation(mOriginalOrientation);

        }

        

    }

    

    static class FullscreenHolder extends FrameLayout {

        

        public FullscreenHolder(Context ctx) {

            super(ctx);

            setBackgroundColor(ctx.getResources().getColor(android.R.color.black));

        }

        

        @Override

        public boolean onTouchEvent(MotionEvent evt) {

            return true;

        }

    }

    

}

 


위 소스로 교체시 WebView에서 동영상 전체화면과 가로/세로는 해결 됩니다.


그 다음 WebView종료시 계속 재생되는 사운드가 문제인데 이부분은 아래 파일을 수정해야 합니다.

"프로젝트명"/cocos2d/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxWebViewHelper.java


[ Cocos2dxWebViewHelper.java File ]


public static void removeWebView(final int index) {

    sCocos2dxActivity.runOnUiThread(new Runnable() {

        @Override

        public void run() {

            Cocos2dxWebView webView = webViews.get(index);

            if (webView != null) {

                webViews.remove(index);

                sLayout.removeView(webView);

                

                // webview를 Destory 해야 사운드 재생이 멈춘다.

                webView.destroy();

                webView = null;

            }

        }

    });

}


removeWebView Method를 위와 같이 수정시 WebView를 remove할 경우 사운드 재생이 멈춥니다.

또는 setStopWebView와 같은 Method를 새로 만들어 사운드 재생만을 멈추게 할수도 있습니다.


위 2가지를 수정하면 정상적으로 유투브 동영상을 재생할 수 있습니다.

cocos2d에서 하루 빨리 수정해주었으면 하내요 ^^


그전에 조금이나마 도움이 될 수 있을 것 같아 공유합니다.


근데 더 큰 문제 점이 있었내요.

Android 문제를 해결 하고 마켓에 올렸는데

유투브 동영상을 제 앱에서 바로 실행하면 앱이 거절 당한다는 메시지가 날라 왔습니다.

유투브 동영상으로 수입을 벌면 안된다는 얘기더군요.


결국 유투브 동영상을 제 앱에 웹브라우저 에서 실행하면 안되고 

유투브 사이트로 이동하여 플레이 하는 걸로 변경하여 해결해야 했습니다.


막상 이렇게 해결 하고 나니 제 앱이 쓸모가 없어졌내요. ㅠㅠ

구글이 점점 앱 제한이 커지는 것 같습니다. 


그래도 안전을 위한 구글에 선택이니 믿고 따라야죠. ^^

반응형

+ Recent posts