react-native : Modal example, share to WeChat

Refer

https://facebook.github.io/react-native/docs/modal.html

No Image, No Truth

modal-share

Full Codes

import React, { Component } from 'react'; import {     Button, 	Modal,     Image,     Keyboard,     NativeModules,     Platform,     StyleSheet,     Text,     TextInput,     TouchableOpacity,     View,     WebView, } from 'react-native';  const { WeChat } = NativeModules;  const SHARE_TO_WXTIMELINE = 0; const SHARE_TO_WXSESSION = 1; const webview = "webview"; const HOME_URL = "https://errong.win";  export default class App extends Component<{}> {    componentWillMount () {     this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => {this.keyboardDidHide()});   }    componentWillUnmount () {     this.keyboardDidHideListener.remove();   }    keyboardDidHide () {     console.log( this.urlText );     if (this.urlText != null) {       this.setState({url:this.urlText});     }   }    constructor(props) {     super(props);     this.state = {shareModalVisible : false, url : HOME_URL, urlBarVisible : true};   }    setShareModalVisible(visible) {     this.setState({shareModalVisible : visible});   }    onShare(scene) {     this.setShareModalVisible(false); 	this.scene = scene;     if (this.shareMsg == null)       return;     if (WeChat.shareToTimeline)       WeChat.shareToTimeline(this.shareMsg, this.scene, null);   }    onWebViewMessage(event) {     console.warn(event.nativeEvent.data);     let msg;     try {       msg = JSON.parse(event.nativeEvent.data);     } catch (err) {       console.warn(err);       return;     }     if (msg.id == "ABSTRACT_FETCHED")       this.shareMsg = msg;   }    genAbstractJS() {     const genAbstractFunction = function() {       try {         let title;         let description;         let imageUrl;         let msg;         let n = document.querySelector('head title');         if (n)             title = n.innerText;         n = document.querySelector('p');         if (n)             description = n.innerText;         n = document.querySelector('p img');         if (n)             imageUrl = n.src;         if (description && imageUrl) {             msg = { 'id' : 'ABSTRACT_FETCHED',                     'type' : 'textimage',                     'description' : description,                     'imageUrl': imageUrl                   };         } else {            msg = { 'id' : 'ABSTRACT_FETCHED',                    'type' : 'news',                    'webpageUrl' : window.location.href                  };         }         window.postMessage(JSON.stringify(msg), "*");       } catch (err) {         console.warn(err);       }     }     let js = "(" + String(genAbstractFunction) + ")();";     console.log(js);     return js;   }    onLoadEnd() {     this.refs[webview].injectJavaScript(this.genAbstractJS());   }    onUrlBar() {   }    renderUrlBar() {     if (this.state.urlBarVisible) {       return (         <TouchableOpacity style={styles.urlbar} onPress={() => {this.onUrlBar()}}>           <TextInput             style={styles.urlentry}             placeholder="search or input url"             onChangeText={(text) => {this.urlText = text}}           />         </TouchableOpacity>       )     } else {       return null;     }   }    render() {     return (     <View style={{flex:1}}>       {this.renderUrlBar()}       <WebView         ref={webview}         style={{flex:1}}         javaScriptEnabled={true}         onMessage={(event) => {this.onWebViewMessage(event)}}         onLoadEnd={this.onLoadEnd.bind(this)}         source={{uri:this.state.url}}       />       <Button         onPress={() => {this.setShareModalVisible(true)}}         title="Share"         color="#841584"         accessibilityLabel="Social Share"       /> 	  <Modal 		transparent={true} 		visible={this.state.shareModalVisible} 		> 		<View style={styles.sgc}>           <View style={styles.sharegroup}>             <TouchableOpacity style={styles.sharebutton} onPress={() => {this.onShare(SHARE_TO_WXTIMELINE)}}>               <Image                 source={require('./res/img/wxtimeline.png')}               />             </TouchableOpacity>             <TouchableOpacity style={styles.sharebutton} onPress={() => {this.onShare(SHARE_TO_WXSESSION)}}>               <Image                 source={require("./res/img/wxsession.png")}               />             </TouchableOpacity>           </View> 		</View> 	  </Modal>     </View>     );   } }  const styles = StyleSheet.create({   urlbar:{   	backgroundColor:'#fafad2',     borderTopLeftRadius:4,     borderTopRightRadius:4,     borderBottomLeftRadius:4,     borderBottomRightRadius:4,     boderColor : '#C0C0C0',     borderWidth: 1   },   urlentry:{     height: 40   },   sgc:{   	height:100,     width:300,     borderTopLeftRadius:10,     borderTopRightRadius:10,     borderBottomLeftRadius:10,     borderBottomRightRadius:10,     alignSelf: 'center',   	top:400,   	backgroundColor:'#fafad2'   },   sharegroup: {   	flex:1, 	flexDirection: 'row',   	alignItems: 'center',   	justifyContent: 'space-around',   },   sharebutton: {     width:64,     height:64   } }) 

react-native : How to create Image Button

Solution

Use TouchableOpacity, Image and Styles.

Key codes

import React, { Component } from 'react'; import {         Image,     StyleSheet,        TouchableOpacity, } from 'react-native';  <TouchableOpacity     style={styles.sharebutton}     onPress={() => {this.onShare(SHARE_TO_WXTIMELINE)}} >     <Image         source={require('./res/img/wxtimeline.png')}     /> </TouchableOpacity>          

No Image, No Truth

modal-share
See Full sample codes Share to WeXin via Modal

react-natvie run-android --variant=release uncompiled PNG file passed as argument. Must be compiled first into .flat file..

C:\Users\lenger\Desktop\webrowser\android\app\build\intermediates\res\merged\release\drawable-mdpi\res_icon64_appwx_logo
.png: error: uncompiled PNG file passed as argument. Must be compiled first into .flat file..
error: failed parsing overlays.

Task :app:processReleaseResources
Failed to execute aapt
com.android.ide.common.process.ProcessException: Failed to execute aapt

workaround

android\gradle.properties
android.enableAapt2=false

refer

https://github.com/react-navigation/react-navigation/issues/3097

wechat share for react native app on android platform

Register App on weixin open platform

Register your on https://open.weixin.qq.com

While registering your app, you will need app sign signature,
you can refer sign your app for weixin.

You will get your APPID after your app registered.
please keep it.
appsign

prepare wechat sdk for you app

add wechat sdk in android/app/build.gradle

dependencies {     compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+' } 

set up AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 

build native wechat to react native JS

I export wechat as "NativeModules.WeChat" follow below examples
https://facebook.github.io/react-native/docs/native-modules-android.html

The main java codes:

  1. WeChatModule, extends ReactContextBaseJavaModule, implements IWXAPIEventHandler
  2. WeChatPackage, new WeChatModule as NativeModules
  3. MainApplication::getPackages(), new WeChatPackage

Important:
To expose a method to JavaScript a Java method must be annotated using @ReactMethod. The return type of bridge methods is always void. React Native bridge is asynchronous, so the only way to pass a result to JavaScript is by using callbacks or emitting events (see below).

public class WeChatModule extends ReactContextBaseJavaModule implements IWXAPIEventHandler {     // ReactContextBaseJavaModule implementation     @Override     public String getName() {         return "RCTWeChat";     }          // IWXAPIEventHandler implementation     @Override     public void onReq(BaseReq baseReq) {     }      @Override     public void onResp(BaseResp baseResp) {     }               @ReactMethod     public void shareToTimeline(ReadableMap data, Callback callback) {     } } public class WeChatPackage implements ReactPackage {    @Override   public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {     return Collections.emptyList();   }    @Override   public List<NativeModule> createNativeModules(                               ReactApplicationContext reactContext) {     List<NativeModule> modules = new ArrayList<>();      modules.add(new WeChatModule(reactContext));      return modules;   }  } public class MainApplication extends Application implements ReactApplication {    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {     @Override     public boolean getUseDeveloperSupport() {       return BuildConfig.DEBUG;     }      @Override     protected List<ReactPackage> getPackages() {       return Arrays.<ReactPackage>asList(           new MainReactPackage(),           new WeChatPackage()       );     } 

Use in react native JS

import { NativeModules, } from 'react-native'; const { WeChat } = NativeModules; 

Pease avoid RCT prefix issue.

You can get all codes by downloading my example app wechat-share-example.
It is a zip file, after you download it, Remember:

1. replace app id in .\android\app\src\main\java\com\wx\react\WeChatModule.java 2. replace package name to your package name. 3. run npm install before react-native run-android 

The package name in the example is "com.errong.webrowser".
./android/app/BUCK:48: package = "com.errong.webrowser",
./android/app/BUCK:53: package = "com.errong.webrowser",
./android/app/build.gradle:100: applicationId "com.errong.webrowser"
./android/app/src/main/AndroidManifest.xml:2: package="com.errong.webrowser"
./android/app/src/main/java/com/webrowser/MainActivity.java:1:package com.errong.webrowser;
./android/app/src/main/java/com/webrowser/MainApplication.java:1:package com.errong.webrowser;

app id and package name should exactly same to the one you applied at
open.weixin.com which was mentioned at the beginning of this post.
otherwist, share feature maynot work well.

register app id to wechat

let's refer to offical guide

.\android\app\src\main\java\com\wx\react\WeChatModule.java

public class WeChatModule extends ReactContextBaseJavaModule implements IWXAPIEventHandler {     private IWXAPI api = null;      public WeChatModule(ReactApplicationContext context) {         super(context);         String appId = "YOURAPPID";         api = WXAPIFactory.createWXAPI(this.getReactApplicationContext().getBaseContext(), appId, true);         if (api != null)             api.registerApp(appId);     } 

Share to wechat time line

let's refer to offical guide

.\android\app\src\main\java\com\wx\react\WeChatModule.java

   @ReactMethod    public void shareToTimeline(ReadableMap data, Callback callback) {        if (api == null) {            Toast.makeText(getReactApplicationContext(), "App not registered to WeChat", Toast.LENGTH_SHORT).show();            return;        }        WXMediaMessage.IMediaObject mediaObject = _jsonToTextMedia(data);        WXMediaMessage message = new WXMediaMessage();        message.mediaObject = mediaObject;        if (data.hasKey("title"))            message.title = data.getString("title");        if (data.hasKey("description"))            message.description = data.getString("description");        SendMessageToWX.Req req = new SendMessageToWX.Req();        req.message = message;        req.scene = SendMessageToWX.Req.WXSceneTimeline;        req.transaction = UUID.randomUUID().toString();        api.sendReq(req);    } 

App.js

import { NativeModules, } from 'react-native'; const { WeChat } = NativeModules; var msg = {'id' : 'ABSTRACT_FETCHED', 'url' : window.location.href, 'title' : title, 'description' : desc, 'imgurl' : imgurl}; WeChat.shareToTimeline(msg, null); 

Key points

  1. APPID and package name should same to the one you applied at open.weixin.qq.com
    sign your app for weixin
  2. sign your apk with your keystore file before you release.
    Generate Signed android APK for react-native app
  3. all sample codes download here

react-native : Native Modules, name prefix "RCT"works for android too

I tried to export wechat sdk as a native module.
I copied some codes here:
public class WeChatModule extends ReactContextBaseJavaModule implements IWXAPIEventHandler {
  private String appId; 
  public WeChatModule(ReactApplicationContext context) { 
    super(context); 
  @Override     public String getName() { 
    return "RCTWeChat"; 
} 
I used "RCTWeChat" as the module name, I did not know the "RCT" prefix meanings.

ReactContextBaseJavaModule requires that a method called getName is implemented. The purpose of this method is to return the string name of the NativeModule which represents this class in JavaScript.

Then I encountered error in my react-native JS codes.
import {NativeModules} from 'react-native'; const { RCTWeChat } = NativeModules; 
WeChat or NativeModules.RCTWeChat always undefined.

Cause

RCT is a prefix used in react native, it will be removed when exported to JS.
React Native uses RCT as a prefix. In order to avoid name collisions, we recommend using a three-letter prefix other than RCT in your own classes.

Solution

The correct JS codes:
const { WeChat } = NativeModules;

react-native run-android : No connected devices!

  • What went wrong:
    Execution failed for task ':app:installDebug'.

com.android.builder.testing.api.DeviceException: No connected devices!

Cause

ADB driver is not ready

Solution

Install correct driver
adb

Search the heart and Examine the mind

我—耶和华是鉴察人心、试验人肺腑的,要照各人所行的和他作事的结果报应他。 (耶利米书 17:10 和合本)
"I the Lord search the heart and examine the mind, to reward each person according to their conduct, according to what their deeds deserve." (Jeremiah 17:10 NIV)


Photo by Max Bender / Unsplash

fixed: embedded-redis: Unable to run on macOS Sonoma

Issue you might see below error while trying to run embedded-redis for your testing on your macOS after you upgrade to Sonoma. java.la...