Что я смог сделать до сих пор
Я написал следующее bridge
в веб-приложении.
window['bridge'] = {
dispatch: (event: string, payload = '') => {
// I had to use zone.run,
// otherwise angular won't update the UI on
// an event triggered from mobile.
this.zone.run(() => {
this.store.dispatch({type: event, payload: payload});
});
},
ofEvent: (event: string) => {
// I register this event on some global variable
// so that I know which events mobile application listens to.
window['nativeActions'].push(event);
return this.actions.ofType(event);
}
};
Из приложения Android я могу прослушать [Collection] Add Book
следующим образом:
webView.loadUrl("
javascript:bridge.ofEvent('[Collection] Add Book')
.subscribe(function(book) {
android.addBook(JSON.stringify(book.payload));
});
");
Это вызовет мой метод addBook
, и я сохраню книгу в каком-нибудь классе, чтобы использовать ее позже.
@JavascriptInterface
public void addBook(String book) {
Log.i("addBook", book);
this.book = book;
}
Я также добавляю кнопку в приложение для Android, чтобы удалить эту книгу.
webView.evaluateJavascript("
bridge.dispatch('[Collection] Remove Book', "+this.book+")
", null);
С помощью этого куска кода я смог прослушать событие, вызванное веб-приложением, и сохранить результат где-нибудь. Я также смог вызвать какое-то событие из приложения для Android, чтобы удалить книгу в веб-приложении.
Также ранее я упоминал, что зарегистрировал это событие в глобальной переменной.
Я изменил свой @Effect
на следующий
@Effect()
addBookToCollection$: Observable<Action> = this.actions$.pipe(
ofType<AddBook>(CollectionActionTypes.AddBook),
map(action => action.payload),
switchMap(book => {
if (window['nativeActions'].indexOf(CollectionActionTypes.AddBook) > -1) {
return of();
} else {
return this.db
.insert('books', [book])
.pipe(
map(() => new AddBookSuccess(book)),
catchError(() => of(new AddBookFail(book)))
);
}
})
);
С помощью if (window['nativeActions']..)
я смог проверить, зарегистрировано ли мобильное приложение для этого конкретного события. Однако я не буду выполнять этот контроль на каждом @Effect
, которое у меня есть. На данный момент я думаю написать какой-то пользовательский оператор RxJs
, чтобы абстрагироваться от этой проверки из моего effects
. Я чувствую, что близок к ответу, но буду признателен за любой вклад.
Пользовательский оператор RxJs
Я написал следующий пользовательский оператор и решил мою проблему.
export function nativeSwitch(callback) {
return function nativeSwitchOperation(source) {
return Observable.create((subscriber: Observer<any>) => {
let subscription = source.subscribe(value => {
try {
if (window['nativeActions'].indexOf(value.type) > -1) {
subscriber.complete();
} else {
subscriber.next(callback(value));
}
} catch (err) {
subscriber.error(err);
}
},
err => subscriber.error(err),
() => subscriber.complete());
return subscription;
});
};
}
Изменен мой эффект:
@Effect()
addBookToCollection$: Observable<Action> = this.actions$.pipe(
ofType<AddBook>(CollectionActionTypes.AddBook),
nativeSwitch(action => action.payload),
switchMap((book: Book) =>
this.db
.insert('books', [book])
.pipe(
map(() => new AddBookSuccess(book)),
catchError(() => of(new AddBookFail(book)))
)
)
);
Это именно то, что я хочу. Поскольку я вызываю subscriber.complete()
, если данное событие зарегистрировано мобильным приложением, метод в пределах switchMap
никогда не вызывается.
Надеюсь, это кому-нибудь поможет.