'2020/04'에 해당되는 글 2건

  1. 2020.04.27 CEF# JavaScript Binding(JSB)
  2. 2020.04.06 Playback Notifications with ExoPlayer
Windows2020. 4. 27. 16:20

CEF javascript 연동

.NET에서는 다음과 같이 자바스크립트 메서드를 호출한다.

browser.ExecuteScriptAsync("document.body.style.background = 'red';");

browser.ExecuteJavaScriptAsync("(function(){ document.getElementsByName('q')[0].value = 'CefSharp Was Here!'; document.getElementsByName('btnK')[0].click(); })();");

여러개의 프래임으로 구성된 경우 임의 프레임의 스크립트를 다음과 같이 호출 한다.

browser.GetBrowser().GetFrame("SubFrame").ExecuteJavaScriptAsync("document.body.style.background = 'red';");


그럼 언제 자바스크립트를 호출할 수 있는가?

자바스크립트는 V8Context에서만 호출할 수 있다.
IRenderProcessMessageHandler의 OnContextCreated와 OnContextReleased 가 자바스크립트가 호출될 수 있는 환경의 범위를 제공한다. 각 프레임별로 호출되며 frame.IsMain으로 메인프레임여부를 판가름할 수 있다.

OnFrameLoadStart에서 DOM에 접근할 수 있으며 로딩이 완료되기 던에 DOM의 스크립트를 실행할 수 있다.

browser.RenderProcessMessageHandler = new RenderProcessMessageHandler();

public class RenderProcessMessageHandler : IRenderProcessMessageHandler {

  // Wait for the underlying JavaScript Context to be created. This is only called for the main frame.
  // If the page has no JavaScript, no context will be created.
  void IRenderProcessMessageHandler.OnContextCreated(IWebBrowser browserControl, IBrowser browser, IFrame frame)
  {
    const string script = "document.addEventListener('DOMContentLoaded', function(){ alert('DomLoaded'); });";

    frame.ExecuteJavaScriptAsync(script);
  }
}

//Wait for the page to finish loading (all resources will have been loaded, rendering is likely still happening)
browser.LoadingStateChanged += (sender, args) =>
{
  //Wait for the Page to finish loading
  if (args.IsLoading == false)
  {
    browser.ExecuteJavaScriptAsync("alert('All Resources Have Loaded');");
  }
}

//Wait for the MainFrame to finish loading
browser.FrameLoadEnd += (sender, args) =>
{
  //Wait for the MainFrame to finish loading
  if(args.Frame.IsMain)
  {
    args.Frame.ExecuteJavaScriptAsync("alert('MainFrame finished loading');");
  }
};

* 스크립트는 프레임레벨에서 수행되고 모든 페이지는 한개 이상의 프레임으로 구성된다.
* IWebBrowser.ExecuteScriptAsync 확장메서드는 하위호환성을 위해 남겨 있으며 main frame에서 js를 수행하는 숏컷처럼 사용가능하다.
* frame이 자바스크립트를 포함하지 않으면 V8Context가 생성되지 않는다.
* frame이 로드된 후 context가 없는 경우 IFrame.ExecuteJavaScriptAsync를 호출하여 V8Context을 생성할 수 있다.
* OnFrameLoadStart가 호출될때 DOM 로딩이 완료되지 않는다.
* IRenderProcessMessageHandler.OnContextCreated/OnContextReleased는 메인프레임에서만 호출된다.

결과를 리턴하는 자바스크립트 메서드의 호출은 ?

//An extension method that evaluates JavaScript against the main frame.
Task response = await browser.EvaluateScriptAsync(script);
//Evaluate javascript directly against a frame
Task response = await frame.EvaluateScriptAsync(script);

자바스크립트는 비동기로 수행되기 때문에 에러메세지, 결과, 성공플래그등을 포함하는 Task를 반환한다. 
자바스크립트가 수행될때 기본적으로 알아야 할 사항은 다음과 같다.

* 언제 호출하는게 가능한지에 대해 알아야 하며 위에서 설명하였다.
* 프레임레벨에서 스크립트가 수행되고 모든 페이지는 하나이상의 프레임으로 구성된다.
* 스크립트는 렌더프로세스내에서 수행되고 성능상의 이유로 IPC를 통해 전달되고 데이터만 반환한다.
* 프리미티브 타입인 int, double, date, bool과 string이 제공된다.
* 결과로 객체가 제공되고 IDictionary<string, object>형태로 접근을 더 용이하게하기 위해 dynamic 키워드가 제공된다.
* 프리미티브타입이나 앞서 얘기한 객체가 IList

<script type="text/javascript">

(async function() {

  await CefSharp.BindObjectAsync("boundAsync");

  // 

  boundAsync.add(16, 5).then(function (actualResult) {

    const expectedResult = 21;

    assert.equal(expectedResult, actualResult, "Add 16 + 5 resulte in " + expectedResult);

  });

})();

</script>

 

CefSharp.BindObjectAsync가 호출되면 JavascriptObjectRepository가 주어진 이름으로 인스턴스가 등록되어 있는지 확인한다. 만일 등록이 안되어 있다면 ResolveObject이벤트가 발생한다. 파라메터 없이 CefSharp.BindObjectAsync가 호출되면 등록된 경우 바운드가 되고 등록이 안되었으면 ObjectName을 All로 설정하여 ResolveObject가 모두 호출된다.

example) https://github.com/cefsharp/CefSharp.MinimalExample/tree/demo/javascriptbinding

 

 

Posted by 삼스

댓글을 달아 주세요

Android/App개발2020. 4. 6. 14:45

https://medium.com/google-exoplayer/playback-notifications-with-exoplayer-a2f1a18cf93b

 

PlayerNotificationManager를 통해 미디어재생 시 알림센터에 정보를 표시하고 제어할 수 있다.

1. PlayerNotificationManager인스턴스 생성
2. PlayerNotificationManager.MediaDescriptionAdapter 로 재생중인 미디어 아이템 정보를 제공
3. 플레이어에 연결, 리소스가 소거되었을 때는 연결해제

PlayerNotificationManager 인스턴스 생성
 activity나 fragment의 onCreate에서 생성한다. 

@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  ...
  playerNotificationManager = new PlayerNotificationManager(
      this,
      new DescriptionAdapter(), 
      CHANNEL_ID,
      NOTIFICATION_ID);
}

채널아이디, 알림아이디, 그리고 재생중인 미디어 정보를 제공하기 위해 MediaDescriptionAdapter를 확장한 DescriptionAdapter를 파라메터로 넘긴다.

private class DescriptionAdapter implements
    PlayerNotificationManager.MediaDescriptionAdapter {
    
  @Override
  public String getCurrentContentTitle(Player player) {
    int window = player.getCurrentWindowIndex();
    return getTitle(window);
  }

  @Nullable
  @Override
  public String getCurrentContentText(Player player) {
    int window = player.getCurrentWindowIndex();
    return getDescription(window);
  }

  @Nullable
  @Override
  public Bitmap getCurrentLargeIcon(Player player,
      PlayerNotificationManager.BitmapCallback callback) {
    int window = player.getCurrentWindowIndex();
    Bitmap largeIcon = getLargeIcon(window);
    if (largeIcon == null && getLargeIconUri(window) != null) {
      // load bitmap async
      loadBitmap(getLargeIconUri(window), callback); 
      return getPlaceholderBitmap();
    }
    return largeIcon;
  }

  @Nullable
  @Override
  public PendingIntent createCurrentContentIntent(Player player) {
    int window = player.getCurrentWindowIndex();
    return createPendingIntent(window);
  }
}

플레이어에 연결은 다음과 같이 한다.

player = ExoPlayerFactory.newSimpleInstance(renderersFactory, trackSelector);
playerNotificationManager.setPlayer(player);

플레이어가 해제되기 전에 먼저 연결을 끊어야 한다.

playerNotificationManager.setPlayer(null);
player.release();
player = null;


커스텀하기

 앱의 테마에 맞도록 알림을 커스텀하는 다양한 방법이 존재한다. 재생컨트롤의 동작여부를 설정하고 알림속성을 설정할 수 있도록 매니져가 기능을 제공한다. 이 속성들은 기본값을 가지고 있고 쉽게 바꿀수 있다.

재생컨트롤 액션들

 기본 컨트롤액션을 제공한다. 재생/일시정지, FF/REW, Next/Previous, Stop등이 있으며 생략도 가능하다

// omit skip previous and next actions
playerNotificationManager.setUseNavigationActions(false);
// omit fast forward action by setting the increment to zero
playerNotificationManager.setFastForwardIncrementMs(0);
// omit rewind action by setting the increment to zero
playerNotificationManager.setRewindIncrementMs(0);
// omit the stop action
playerNotificationManager.setStopAction(null);

커스텀액션도 CustionActionReceiver를 확장하여 구현하여 PlayerNotificationManager 생성자의 5번째 파라메터로 넣어서 구현 가능하다.

알림 속성

 알림매니저는 UI와 알림의 동작의 setter를 제공한다. 이는 NotificationCompat.Builder의 속성에 상응한다.

manager.setOngoing(false);
manager.setColor(Color.BLACK);
manager.setColorized(true);
manager.setUseChronometer(false);
manager.setSmallIcon(R.drawable.exo_notification_small_icon);
manager.setBadgeIconType(NotificationCompat.BADGE_ICON_NONE);
manager.setVisibility(NotificationCompat.VISIBILITY_PRIVATE);

MediaSession

 최종적으로 Google Assistant등을 지원하기 위해 MediaSession API를 사용하고 있다면 media style 알림의 장점을 모두 취하기 위해 session에 token을 셋팅할수 있다.

 playerNotificationManager.setMediaSessionToken(token);




 

Playback Notifications with ExoPlayer

Displaying a notification with playback controls is a best practice for media apps on Android. For audio playback in the background it’s…

medium.com

 

Posted by 삼스

댓글을 달아 주세요