I'm trying to integrate a SDK in my react native app, and i'm little bit confused, as documentation says, i know that i have to write a bridge in order to use the native library in react native.
here is what i've done:
I put the sdk-file.aar in android/app/libs.
I created libraryModule.java and libraryPackage.java
with the folowing code
libraryModule.java
package com.myapp.android;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.Map;
import java.util.HashMap;
import com.facebook.react.bridge.Promise;
import com.ekassir.mirpaysdk.client.MirApp;
public class MirPayModule extends ReactContextBaseJavaModule {
MirPayModule(ReactApplicationContext context) {
super(context);
}
#Override
public String getName() {
return "MirPaySdk";
}
#ReactMethod
{
}
}. // I think some methods should be here
My question is: should i recreate all methods present in the library ?
I'm receiving the sdk from a bank, should i recreate all methods with #ReactMethod tag in order to have the possibility to access them in react native ?
Am i missing something in the process of integration ?
Related
I'm trying to add an ad to my app.
Following this guide, I've ran into trouble with "Initialize the Mobile Ads SDK" for it wants me to import some Java code:
package ...
import ...
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.initialization.InitializationStatus;
import com.google.android.gms.ads.initialization.OnInitializationCompleteListener;
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MobileAds.initialize(this, new OnInitializationCompleteListener() {
#Override
public void onInitializationComplete(InitializationStatus initializationStatus) {
}
});
}
}
and I've got a Javascript project:
import React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import Home from "./screens/home"
import heads from "./screens/heads"
import tails from "./screens/tails"
//problems start from here. This is the copied text from https://developers.google.com/admob/android/quick-start?hl=es#import_the_mobile_ads_sdk
package ...
import ...
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.initialization.InitializationStatus;
import com.google.android.gms.ads.initialization.OnInitializationCompleteListener;
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MobileAds.initialize(this, new OnInitializationCompleteListener() {
#Override
public void onInitializationComplete(InitializationStatus initializationStatus) {
}
});
}
}
//this is where they end
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen
name="Home"
component={Home}
options={{headerShown: false}} />
<Stack.Screen
name="tails"
component={tails}
options={{headerShown: false}} />
<Stack.Screen
name="heads"
component={heads}
options={{headerShown: false}} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
const Stack = createStackNavigator();
Errors
This is the output when trying to access the app:
App.js: Unexpected reserved word 'package' (10:0)
8 |
9 | //problems start from here. This is the copied text from https://developers.google.com/admob/android/quick-start?hl=es#import_the_mobile_ads_sdk
> 10 | package ...
| ^
11 | import ...
12 | import com.google.android.gms.ads.MobileAds;
13 | import com.google.android.gms.ads.initialization.InitializationStatus;
I'm not sure if I should be converting JAVA into JAVASCRIPT for this purpose in particular. I've found nothing on the internet around it, and there's no "translator" for programming languages as far as I know.
I'm clueless. I've already tried the same thing with KOTLIN but it failed as well. I don't want to add the KOTLIN code and the errors because it says that my post is mostly code (and it certainly is, but I don't know towards which direction to go from here)
Thank you!
Ok so it looks as though you're trying to put Java and JavaScript code in the same file, which won't work.
In your included javascript project snippet, this whole section:
//problems start from here. This is the copied text from https://developers.google.com/admob/android/quick-start?hl=es#import_the_mobile_ads_sdk
package ...
import ...
import com.google.android.gms.ads.MobileAds;
import com.google.android.gms.ads.initialization.InitializationStatus;
import com.google.android.gms.ads.initialization.OnInitializationCompleteListener;
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MobileAds.initialize(this, new OnInitializationCompleteListener() {
#Override
public void onInitializationComplete(InitializationStatus initializationStatus) {
}
});
}
}
//this is where they end
Would need to be in a separate Java file.
Now, I see you're using react-native. I would need to know if you're using standard react-native or an expo managed project.
If you are using an expo managed project, there is already a package made for admob, just follow the instructions in the documentation here: https://docs.expo.io/versions/v39.0.0/sdk/admob/
If you are just using react native, it gets quite a bit more complicated. The docs that you provided are intended for Java / Kotlin native development opposed to native development through react, so it will be hard for you to get it working using the code from that document. This link should help you get it working for react-native: https://dev.to/srajesh636/how-to-show-ads-in-react-native-lcj
*note that in the included docs provided by google, where you see package ... and import ..., you're expected to fill in your actual package name, and any other imports you need for the class.
Hopefully this has provided some insight on your problem, let me know if there are still any issues.
I'm trying to wrap this simple API: https://github.com/github-tools/github, just for study purpose. So, I created this external classes:
package index
import com.github.jesty.githubapi.Result
import com.github.jesty.githubapi.User
import kotlin.js.Promise
external class GitHub(user: User) {
fun getUser(): GHUser
}
external class GHUser {
fun listStarredRepos(): Promise<Result>
}
In a simple KotlinJS project everything is ok, but when I try to use in a project created with Create React Kotlin App I have the error below:
ReferenceError: GitHub is not defined
Just solved, I need to annotate the external class with #JsModule("github-api"):
package com.github.jesty.githubapi
import kotlin.js.Promise
#JsModule("github-api")
external class GitHub(user: User) {
fun getUser(): GHUser
}
#JsModule("github-api")
external class GHUser {
fun listStarredRepos(): Promise<Result>
}
I'm building an app using React Native which requires a service that detects missed calls and sends that on the server and then shows a notification in phone status bar.
I decided to write my own extension that will handle that because I didn't found any node module that will be sufficient for my needs. Unfortunately, service is being killed after some hours and I can't handle with that. Basically, I'm JavaScript developer and native code in Java is for me like a black hole so I'll be very grateful for any help.
The app is using Headless JS for sending data to the server, basically all extension was based on articles:
http://www.learn-android-easily.com/2013/06/detect-missed-call-in-android.html
https://codeburst.io/simple-android-call-recorder-in-react-native-headlessjs-task-614bcc56efc4
I've found some similar topics:
Android service process being killed after hours
https://fabcirablog.weebly.com/blog/creating-a-never-ending-background-service-in-android
And tried to follow the instructions described there, but all of these solutions are related only with native code without using React Native and Headless JS so I don't know if that solutions will be ok for app that using React Native or probably (for sure) I'm doing something wrong.
Here is my AndroidManifest part responsible for Service and BroadcastReceiver:
(...)
<service android:name="com.app.service.CallLogService" />
<receiver android:name="com.app.receiver.CallLogReceiver">
<intent-filter android:priority="0">
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
(...)
My CallLogService class:
package com.app.service;
import android.content.Intent;
import android.os.Bundle;
import com.facebook.react.HeadlessJsTaskService;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.jstasks.HeadlessJsTaskConfig;
import javax.annotation.Nullable;
public class CallLogService extends HeadlessJsTaskService {
#Nullable
protected HeadlessJsTaskConfig getTaskConfig(Intent intent) {
Bundle extras = intent.getExtras();
return new HeadlessJsTaskConfig(
"CallLog",
extras != null ? Arguments.fromBundle(extras) : null,
5000,
true
);
}
}
My CallLogReceiver class:
package com.app.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.app.service.CallLogService;
import com.facebook.react.HeadlessJsTaskService;
public final class CallLogReceiver extends BroadcastReceiver {
public final void onReceive(Context context, Intent intent) {
(...)
callerPhoneNumber = intent.getStringExtra("incoming_number");
Intent callIntent = new Intent(context, CallLogService.class);
callIntent.putExtra("phone_number", callerPhoneNumber);
context.startService(callIntent);
HeadlessJsTaskService.acquireWakeLockNow(context);
}
}
I'm using React Native 0.50.3
At the end I have an additional question. I noticed that after restart phone the service is also killed. How can I prevent such situation too?
Edit:
I noticed that if app is in background then after sending request the response is not recorded.
But after firing a new request the application is getting response from previous request. I'm using axios for doing ajax.
Eg.
let callAjax = function(counter){
console.log('Request ' + counter);
axios.get('/user?ID=12345')
.then(function (resp) {
console.log('Response ' + counter);
})
};
callAjax(1);
setTimeout(() => {
callAjax(2);
}, 5000);
When app is in background then I have:
Request 1
After 5 sec
Response 1 Request 2
When app is in foreground then everything is ok:
Request 1 Response 1
After 5 sec
Request 2 Response 2
I created an app using the create-react-kotlin-app command and it loads in Chrome fine. I added the React Material UI package via NPM and that was successful. Now how do I use the Material UI module in my component?
Normally with JavaScript, it's a simple import Button from '#material-ui/core/Button' at the top of the component's file, but Kotlin doesn't like that.
How do I translate that line to Kotlin? I am not using Gradle.
I have been struggling with this problem for days now. I came up with the following solution. First we will see multiple ways to declare external modules, then I will show how to use them
.
Consider the following javascript code
import Button from '#material-ui/core/Button' // this means button is exported as default
This will be imported in kotlin in the following ways
Button.kt
#file:JsModule("#material-ui/core/Button")
#file:JsNonModule
package com.mypckage.mykillerapp
import react.Component
import react.RProps
import react.RState
import react.ReactElement
#JsName("default") // because it was exported as default
external val Button : RClass<RProps>
// way 2
#JsName("default")
external class Button : Component<RProps,RState> {
override fun render(): ReactElement?
}
But again, if the statement intend for kotlin has to match the javascript import statement bellow,
import { Button } from "material-ui" // not exported as default
We use the following approach: Button.kt
#file:JsModule("material-ui")
#file:JsNonModule
package com.mypckage.mykillerapp
import react.Component
import react.RProps
import react.RState
import react.ReactElement
// way 1
#JsName("Button") // because it was exported as default
external val Button : RClass<RProps>
// way 2
#JsName("Button")
external class Button : Component<RProps,RState> {
override fun render(): ReactElement?
}
once you have declared on how to use your components, you can just use them as follows:
//way 1:
fun RBuilder.render() {
div {
Button {
attrs.asDynamic().className="submit-button"
+"Submit"
}
}
}
//way 2:
fun RBuilder.render() {
div {
child(Button::class) {
attrs.asDynamic().className="submit-button"
+"Submit"
}
}
}
great. you have imported your component. But until then your are not relying on kotlin type safety and even code completion, to achieve that, you have to go to extra length
as shown bellow
external interface ButtonProps: RProps {
var className : String
var onClick: (Event?)->Unit
var color: String
// . . .
var href: String
}
then go ahead and declare your button as
#JsModule("#material-ui/core/Button")
#JsNonModule
#JsName("default") // because it was exported as default
external val Button : RClass<ButtonProps>
and you can now use it with type safety and code completion as shown bellow
fun RBuilder.render() {
div {
Button {
attrs {
className = "submit-button"
onClick = {
window.alert("Vois La")
}
}
+"Submit"
}
}
}
Hope this helps. Happy coding
EDIT:
There is a community wrapper for material-ui components here
HINT:
Use way 1, as you can see, it is less verbose
The Kotlin way for importing dependencies is close to standard JS importing:
import React from 'react';
export function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
Based on Creating a simple React component with Kotlin.
package hello
import react.*
import react.dom.*
fun RBuilder.hello(name: String) {
h1 {
+"Hello, $name"
}
}
Usually (as Kotlin is Java-based) it uses Gradle tool to handle dependencies:
// part of build.gradle
kotlinFrontend {
// ...
npm {
// ...
dependency("react")
dependency("react-dom")
dependency("react-router")
dependency("react-markdown")
devDependency("css-loader")
devDependency("babel-core")
// ...
}
And are referenced like above:
HomeView.kt:
// https://github.com/Kotlin/kotlin-fullstack-sample/blob/master/frontend/src/org/jetbrains/demo/thinkter/HomeView.kt
import kotlinx.html.*
import org.jetbrains.demo.thinkter.model.*
import react.*
import react.dom.*
import kotlinx.coroutines.experimental.launch
ReactMarkdown.kt:
// https://github.com/Kotlin/kotlin-fullstack-sample/blob/master/frontend/src/org/jetbrains/demo/thinkter/ReactMarkdown.kt
package org.jetbrains.demo.thinkter
import react.*
private val ReactMarkdown: dynamic = runtime.wrappers.require("react-markdown")
Based on: kotlin-fullstack-sample
In create-react-kotlin-app additionally faced the possibility of importing with #JsModule() annotation, while dependencies managing is handled in standard way via package.json:
// src/logo/Logo.kt (outcome of creating new app)
package logo
import react.*
import react.dom.*
import kotlinext.js.*
import kotlinx.html.style
#JsModule("src/logo/react.svg")
external val reactLogo: dynamic
#JsModule("src/logo/kotlin.svg")
external val kotlinLogo: dynamic
And can be also successfully used for JS libraries importing.
Another way would be to use kotlinext.js.*:
// index/index.kt
import kotlinext.js.*
fun main(args: Array<String>) {
requireAll(require.context("src", true, js("/\\.css$/")))
// ...
}
Which provides also require(module: String) function.
I'm testing a React component using Jest. The test runs fine, but I get a few console.warn messages that are very annoying. I'm not using either PropTypes or createClass myself, so I'm suspecting this comes from some library. Is there some way to figure out where they are coming from, or suppress them?
PASS src/__tests__/title.test.ts
● Console
console.warn node_modules/react/lib/lowPriorityWarning.js:40
Warning: Accessing PropTypes via the main React package is deprecated, and will be removed in React v16.0. Use the latest available v15.* prop-types package from npm instead. For info on usage, compatibility, migration and more, see
console.warn node_modules/react/lib/lowPriorityWarning.js:40
Warning: Accessing createClass via the main React package is deprecated, and will be removed in React v16.0. Use a plain JavaScript class instead. If you're not yet ready to migrate, create-react-class v15.* is available on npm as a temporary, drop-in replacement. For more info see
The test looks like this
import { shallow } from "enzyme";
import * as React from "react";
import {Title} from "../components/title";
describe("Testing title component", () => {
it("renders", () => {
const titleElement: React.ReactElement<{}> = React.createElement(Title);
const component = shallow(titleElement);
const text = component.text();
expect(text).toBe("test");
});
});
and the component looks like this
import * as React from "react";
export class Title extends React.Component<{}, {}> {
constructor(props: {}) {
super(props);
}
public render(): React.ReactElement<{}> {
return <p>test</p>;
}
}
Importing using * (import * as) access all the props on React, including PropTypes and createClass, which is eventually causing the warnings.
Try to write import React from 'react' instead.
https://github.com/airbnb/enzyme/issues/1065