Kaynağa Gözat

Merge branch 'bundleReload'

Guy Carmeli 8 yıl önce
ebeveyn
işleme
7263e1b4cf

+ 13
- 0
android/app/src/main/java/com/reactnativenavigation/activities/BaseReactActivity.java Dosyayı Görüntüle

1
 package com.reactnativenavigation.activities;
1
 package com.reactnativenavigation.activities;
2
 
2
 
3
+import android.content.BroadcastReceiver;
4
+import android.content.Context;
3
 import android.content.Intent;
5
 import android.content.Intent;
6
+import android.content.IntentFilter;
4
 import android.content.res.Configuration;
7
 import android.content.res.Configuration;
5
 import android.os.Build;
8
 import android.os.Build;
6
 import android.os.Bundle;
9
 import android.os.Bundle;
26
 import com.facebook.react.bridge.ReadableMap;
29
 import com.facebook.react.bridge.ReadableMap;
27
 import com.facebook.react.bridge.WritableMap;
30
 import com.facebook.react.bridge.WritableMap;
28
 import com.facebook.react.common.ReactConstants;
31
 import com.facebook.react.common.ReactConstants;
32
+import com.facebook.react.devsupport.DevServerHelper;
29
 import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
33
 import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
30
 import com.facebook.react.shell.MainReactPackage;
34
 import com.facebook.react.shell.MainReactPackage;
31
 import com.reactnativenavigation.BuildConfig;
35
 import com.reactnativenavigation.BuildConfig;
367
         return super.onKeyUp(keyCode, event);
371
         return super.onKeyUp(keyCode, event);
368
     }
372
     }
369
 
373
 
374
+    /**
375
+     * Called after bundle was reloaded. This is a good chance to clean up previously connected react views.
376
+     */
377
+    public void onJSBundleReloaded() {
378
+        removeAllReactViews();
379
+    }
380
+
381
+    protected abstract void removeAllReactViews();
382
+
370
     @Override
383
     @Override
371
     public void onBackPressed() {
384
     public void onBackPressed() {
372
         if (getScreenStackSize() > 1) {
385
         if (getScreenStackSize() > 1) {

+ 7
- 0
android/app/src/main/java/com/reactnativenavigation/activities/BottomTabActivity.java Dosyayı Görüntüle

267
         }
267
         }
268
         this.onTabSelected(0, false);
268
         this.onTabSelected(0, false);
269
     }
269
     }
270
+
271
+    @Override
272
+    protected void removeAllReactViews() {
273
+        for (ScreenStack screenStack : mScreenStacks) {
274
+            screenStack.removeAllReactViews();
275
+        }
276
+    }
270
 }
277
 }

+ 4
- 0
android/app/src/main/java/com/reactnativenavigation/activities/RootActivity.java Dosyayı Görüntüle

45
         return 0;
45
         return 0;
46
     }
46
     }
47
 
47
 
48
+    @Override
49
+    public void removeAllReactViews() {
50
+
51
+    }
48
 }
52
 }

+ 5
- 0
android/app/src/main/java/com/reactnativenavigation/activities/SingleScreenActivity.java Dosyayı Görüntüle

103
     public int getScreenStackSize() {
103
     public int getScreenStackSize() {
104
         return mScreenStack.getStackSize();
104
         return mScreenStack.getStackSize();
105
     }
105
     }
106
+
107
+    @Override
108
+    protected void removeAllReactViews() {
109
+        mScreenStack.removeAllReactViews();
110
+    }
106
 }
111
 }

+ 5
- 1
android/app/src/main/java/com/reactnativenavigation/activities/TabActivity.java Dosyayı Görüntüle

1
 package com.reactnativenavigation.activities;
1
 package com.reactnativenavigation.activities;
2
 
2
 
3
-import android.support.design.widget.CoordinatorLayout;
4
 import android.support.v4.view.ViewPager;
3
 import android.support.v4.view.ViewPager;
5
 import android.view.Menu;
4
 import android.view.Menu;
6
 import android.view.ViewGroup;
5
 import android.view.ViewGroup;
69
         return ret;
68
         return ret;
70
     }
69
     }
71
 
70
 
71
+    @Override
72
+    public void removeAllReactViews() {
73
+
74
+    }
75
+
72
     @Override
76
     @Override
73
     public void push(Screen screen) {
77
     public void push(Screen screen) {
74
         super.push(screen);
78
         super.push(screen);

+ 84
- 0
android/app/src/main/java/com/reactnativenavigation/core/RctManager.java Dosyayı Görüntüle

1
 package com.reactnativenavigation.core;
1
 package com.reactnativenavigation.core;
2
 
2
 
3
 import android.app.Application;
3
 import android.app.Application;
4
+import android.util.Log;
4
 
5
 
5
 import com.facebook.react.LifecycleState;
6
 import com.facebook.react.LifecycleState;
6
 import com.facebook.react.ReactInstanceManager;
7
 import com.facebook.react.ReactInstanceManager;
7
 import com.facebook.react.ReactPackage;
8
 import com.facebook.react.ReactPackage;
9
+import com.facebook.react.bridge.JavaJSExecutor;
8
 import com.facebook.react.bridge.ReactContext;
10
 import com.facebook.react.bridge.ReactContext;
9
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
11
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
10
 import com.facebook.react.bridge.WritableMap;
12
 import com.facebook.react.bridge.WritableMap;
13
+import com.facebook.react.devsupport.DevSupportManager;
14
+import com.facebook.react.devsupport.ReactInstanceDevCommandsHandler;
11
 import com.reactnativenavigation.activities.BaseReactActivity;
15
 import com.reactnativenavigation.activities.BaseReactActivity;
12
 import com.reactnativenavigation.core.objects.Screen;
16
 import com.reactnativenavigation.core.objects.Screen;
17
+import com.reactnativenavigation.utils.ContextProvider;
18
+import com.reactnativenavigation.utils.ReflectionUtils;
13
 
19
 
14
 import static com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
20
 import static com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
15
 
21
 
17
  * Created by guyc on 22/02/16.
23
  * Created by guyc on 22/02/16.
18
  */
24
  */
19
 public class RctManager {
25
 public class RctManager {
26
+    private static final String TAG = "RctManager";
20
     private static final String KEY_EVENT_ID = "id";
27
     private static final String KEY_EVENT_ID = "id";
21
     private static RctManager sInstance;
28
     private static RctManager sInstance;
22
 
29
 
68
         }
75
         }
69
 
76
 
70
         mReactManager = builder.build();
77
         mReactManager = builder.build();
78
+        if (reactActivity.getUseDeveloperSupport()) {
79
+            setupDevSupportHandler(mReactManager);
80
+        }
71
         return mReactManager;
81
         return mReactManager;
72
     }
82
     }
73
 
83
 
84
+    /**
85
+     * Inject our CustomDevCommandsHandler to {@code reactInstanceManager} so we can detect when the bundle was
86
+     * parsed and is about to load.
87
+     * @param reactInstanceManager
88
+     */
89
+    private void setupDevSupportHandler(ReactInstanceManager reactInstanceManager) {
90
+        final ReactInstanceDevCommandsHandler devInterface = (ReactInstanceDevCommandsHandler)
91
+                ReflectionUtils.getDeclaredField(reactInstanceManager, "mDevInterface");
92
+        if (devInterface == null) {
93
+            Log.e(TAG, "Could not get field mDevInterface");
94
+            return;
95
+        }
96
+
97
+        // Create customDevCommandsHandler
98
+        CustomDevCommandsHandler customDevCommandsHandler = new CustomDevCommandsHandler(devInterface);
99
+        boolean success = ReflectionUtils.setField(reactInstanceManager, "mDevInterface", customDevCommandsHandler);
100
+        if (!success) {
101
+            Log.e(TAG, "Could not set field mDevInterface");
102
+            return;
103
+        }
104
+
105
+        // Set customDevCommandsHandler in devSupportManager. Fun =).
106
+        DevSupportManager devSupportManager = (DevSupportManager)
107
+                ReflectionUtils.getDeclaredField(reactInstanceManager, "mDevSupportManager");
108
+        if (devSupportManager == null) {
109
+            Log.e(TAG, "Could not get field mDevSupportManager");
110
+            return;
111
+        }
112
+
113
+        success = ReflectionUtils.setField(devSupportManager, "mReactInstanceCommandsHandler", customDevCommandsHandler);
114
+        if (!success) {
115
+            Log.e(TAG, "Could not set field mReactInstanceCommandsHandler");
116
+        }
117
+    }
118
+
74
     public <T extends ReactContextBaseJavaModule> T getNativeModule(Class<T> nativeModuleClass) {
119
     public <T extends ReactContextBaseJavaModule> T getNativeModule(Class<T> nativeModuleClass) {
75
         if (mReactManager == null || mReactManager.getCurrentReactContext() == null) {
120
         if (mReactManager == null || mReactManager.getCurrentReactContext() == null) {
76
             return null;
121
             return null;
113
         mReactManager = null;
158
         mReactManager = null;
114
         sInstance = null;
159
         sInstance = null;
115
     }
160
     }
161
+
162
+    /**
163
+     * Proxy for {@link ReactInstanceDevCommandsHandler} used by {@link DevSupportManager} for requesting React
164
+     * instance recreation. Used to notify {@link BaseReactActivity} that the bundle has been reloaded.
165
+     */
166
+    private static class CustomDevCommandsHandler implements ReactInstanceDevCommandsHandler {
167
+        private ReactInstanceDevCommandsHandler mCommandsHandler;
168
+
169
+        public CustomDevCommandsHandler(ReactInstanceDevCommandsHandler commandsHandler) {
170
+            mCommandsHandler = commandsHandler;
171
+        }
172
+
173
+        @Override
174
+        public void onReloadWithJSDebugger(JavaJSExecutor.Factory proxyExecutorFactory) {
175
+            onJSBundleReloaded();
176
+            mCommandsHandler.onReloadWithJSDebugger(proxyExecutorFactory);
177
+        }
178
+
179
+        @Override
180
+        public void onJSBundleLoadedFromServer() {
181
+            onJSBundleReloaded();
182
+            mCommandsHandler.onJSBundleLoadedFromServer();
183
+        }
184
+
185
+        /**
186
+         * Detach previously added ReactRootViews before handling bundle.
187
+         */
188
+        private void onJSBundleReloaded() {
189
+            BaseReactActivity context = ContextProvider.getActivityContext();
190
+            if (context != null) {
191
+                context.onJSBundleReloaded();
192
+            }
193
+        }
194
+
195
+        @Override
196
+        public void toggleElementInspector() {
197
+            mCommandsHandler.toggleElementInspector();
198
+        }
199
+    }
116
 }
200
 }
117
 
201
 

+ 0
- 2
android/app/src/main/java/com/reactnativenavigation/utils/IconUtils.java Dosyayı Görüntüle

1
 package com.reactnativenavigation.utils;
1
 package com.reactnativenavigation.utils;
2
 
2
 
3
 import android.content.Context;
3
 import android.content.Context;
4
-import android.content.res.Resources;
5
 import android.graphics.Bitmap;
4
 import android.graphics.Bitmap;
6
 import android.graphics.BitmapFactory;
5
 import android.graphics.BitmapFactory;
7
 import android.graphics.drawable.BitmapDrawable;
6
 import android.graphics.drawable.BitmapDrawable;
8
 import android.graphics.drawable.Drawable;
7
 import android.graphics.drawable.Drawable;
9
 import android.net.Uri;
8
 import android.net.Uri;
10
-import android.util.DisplayMetrics;
11
 
9
 
12
 import com.reactnativenavigation.BuildConfig;
10
 import com.reactnativenavigation.BuildConfig;
13
 
11
 

+ 25
- 4
android/app/src/main/java/com/reactnativenavigation/utils/ReflectionUtils.java Dosyayı Görüntüle

1
 package com.reactnativenavigation.utils;
1
 package com.reactnativenavigation.utils;
2
 
2
 
3
 import java.lang.reflect.Field;
3
 import java.lang.reflect.Field;
4
+import java.lang.reflect.Method;
4
 
5
 
5
 /**
6
 /**
6
  * Created by guyc on 14/04/16.
7
  * Created by guyc on 14/04/16.
7
  */
8
  */
8
 public class ReflectionUtils {
9
 public class ReflectionUtils {
9
 
10
 
10
-    public static boolean setBooleanField(Object obj, String name, Boolean value) {
11
+    public static boolean setField(Object obj, String name, Object value) {
11
         Field field;
12
         Field field;
12
         try {
13
         try {
13
             field = obj.getClass().getDeclaredField(name);
14
             field = obj.getClass().getDeclaredField(name);
14
             field.setAccessible(true);
15
             field.setAccessible(true);
15
             field.set(obj, value);
16
             field.set(obj, value);
16
             return true;
17
             return true;
17
-        } catch (NoSuchFieldException e) {
18
-            e.printStackTrace();
19
-        } catch (IllegalAccessException e) {
18
+        } catch (Exception e) {
20
             e.printStackTrace();
19
             e.printStackTrace();
21
         }
20
         }
22
         return false;
21
         return false;
23
     }
22
     }
23
+
24
+    public static Object getDeclaredField(Object obj, String fieldName) {
25
+        try {
26
+            Field f = obj.getClass().getDeclaredField(fieldName);
27
+            f.setAccessible(true);
28
+            return f.get(obj);
29
+        } catch (Exception e) {
30
+            e.printStackTrace();
31
+        }
32
+        return null;
33
+    }
34
+
35
+    public static Object invoke(Object object, String methodName) {
36
+        try {
37
+            Method method = object.getClass().getDeclaredMethod(methodName);
38
+            method.setAccessible(true);
39
+            return method.invoke(object);
40
+        } catch (Exception e) {
41
+            e.printStackTrace();
42
+        }
43
+        return null;
44
+    }
24
 }
45
 }

+ 7
- 3
android/app/src/main/java/com/reactnativenavigation/views/RctView.java Dosyayı Görüntüle

67
      */
67
      */
68
     public void onTemporallyRemovedFromScreen() {
68
     public void onTemporallyRemovedFromScreen() {
69
         // Hack in order to prevent the react view from getting unmounted
69
         // Hack in order to prevent the react view from getting unmounted
70
-        ReflectionUtils.setBooleanField(mReactRootView, "mAttachScheduled", true);
70
+        ReflectionUtils.setField(mReactRootView, "mAttachScheduled", true);
71
     }
71
     }
72
 
72
 
73
     /**
73
     /**
75
      * executed and componentWillUnmount is called
75
      * executed and componentWillUnmount is called
76
      */
76
      */
77
     public void onRemoveFromScreen() {
77
     public void onRemoveFromScreen() {
78
-        ReflectionUtils.setBooleanField(mReactRootView, "mAttachScheduled", false);
78
+        ReflectionUtils.setField(mReactRootView, "mAttachScheduled", false);
79
     }
79
     }
80
 
80
 
81
     /**
81
     /**
83
      * executed and componentWillUnmount is called
83
      * executed and componentWillUnmount is called
84
      */
84
      */
85
     public void onReAddToScreen() {
85
     public void onReAddToScreen() {
86
-        ReflectionUtils.setBooleanField(mReactRootView, "mAttachScheduled", false);
86
+        ReflectionUtils.setField(mReactRootView, "mAttachScheduled", false);
87
+    }
88
+
89
+    public void detachFromScreen() {
90
+        ReflectionUtils.invoke(mReactRootView, "onDetachedFromWindow");
87
     }
91
     }
88
 }
92
 }
89
 
93
 

+ 11
- 0
android/app/src/main/java/com/reactnativenavigation/views/ScreenStack.java Dosyayı Görüntüle

165
 
165
 
166
         parent.addView(this, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
166
         parent.addView(this, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
167
     }
167
     }
168
+
169
+    public void removeAllReactViews() {
170
+        while (!mStack.empty()) {
171
+            RctView view = mStack.pop().view;
172
+            // Ensure view will be properly detached and unmounted
173
+            view.onRemoveFromScreen();
174
+            // Unmount the view
175
+            view.detachFromScreen();
176
+        }
177
+        removeAllViews();
178
+    }
168
 }
179
 }