Ответ 1
То, что я смог сделать до сих пор
Я написал следующий 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
, и я 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
чтобы 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
никогда не будет вызван.
Надеюсь, это поможет кому-то.