list) {
Camera.Size size = null;
// if (list != null) {
// for (Camera.Size s : list) {
// Log.i(TAG, "w:" + s.width + ", h:" + s.height);
// }
// }
// Log.e(TAG, "selected size :" + size.width + "x" + size.height);
return size;
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
Log.i(TAG, "onSingleTapUp X:" + e.getX() + ",Y:" + e.getY());
if (mIsReady && focus) {
setFocusAreaIndicator();
try {
mMediaStreamingManager.doSingleTapUp((int) e.getX(), (int) e.getY());
} catch (Exception ex) {
Log.e(TAG, ex.getMessage());
}
return true;
}
return false;
}
@Override
public boolean onZoomValueChanged(float factor) {
if (mIsReady && mMediaStreamingManager.isZoomSupported()) {
mCurrentZoom = (int) (mMaxZoom * factor);
mCurrentZoom = Math.min(mCurrentZoom, mMaxZoom);
mCurrentZoom = Math.max(0, mCurrentZoom);
Log.d(TAG, "zoom ongoing, scale: " + mCurrentZoom + ",factor:" + factor + ",maxZoom:" + mMaxZoom);
if (!mHandler.hasMessages(MSG_SET_ZOOM)) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SET_ZOOM), ZOOM_MINIMUM_WAIT_MILLIS);
return true;
}
}
return false;
}
// @Override
// public boolean onStateHandled(final int state, Object extra) {
// switch (state) {
// case SENDING_BUFFER_HAS_FEW_ITEMS:
// return false;
// case SENDING_BUFFER_HAS_MANY_ITEMS:
// return false;
// }
// return false;
// }
@Override
public void onHostResume() {
mMediaStreamingManager.resume();
}
@Override
public void onHostPause() {
mHandler.removeCallbacksAndMessages(null);
mMediaStreamingManager.pause();
}
@Override
public void onHostDestroy() {
mMediaStreamingManager.destroy();
}
protected Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_START_STREAMING:
new Thread(new Runnable() {
@Override
public void run() {
boolean res = mMediaStreamingManager.startStreaming();
Log.i(TAG, "res:" + res);
}
}).start();
break;
case MSG_STOP_STREAMING:
boolean res = mMediaStreamingManager.stopStreaming();
break;
case MSG_SET_ZOOM:
mMediaStreamingManager.setZoomValue(mCurrentZoom);
break;
default:
Log.e(TAG, "Invalid message");
}
}
};
private void startStreaming() {
mHandler.removeCallbacksAndMessages(null);
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_STREAMING), 50);
}
private void stopStreaming() {
mHandler.removeCallbacksAndMessages(null);
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_STOP_STREAMING), 50);
}
private DnsManager getMyDnsManager() {
IResolver r0 = new DnspodFree();
IResolver r1 = AndroidDnsServer.defaultResolver();
IResolver r2 = null;
try {
r2 = new Resolver(InetAddress.getByName("119.29.29.29"));
} catch (IOException ex) {
ex.printStackTrace();
}
return new DnsManager(NetworkInfo.normal, new IResolver[]{r0, r1, r2});
}
}
================================================
FILE: android/src/main/java/com/pili/rnpili/support/Config.java
================================================
package com.pili.rnpili.support;
import android.content.pm.ActivityInfo;
import com.qiniu.pili.droid.streaming.StreamingProfile;
/**
* Created by jerikc on 15/12/8.
*/
public class Config {
public static final boolean DEBUG_MODE = false;
public static final boolean FILTER_ENABLED = false;
public static final int ENCODING_LEVEL = StreamingProfile.VIDEO_ENCODING_HEIGHT_480;
public static final int SCREEN_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
public static final String EXTRA_KEY_STREAM_JSON = "stream_json_str";
public static final String HINT_ENCODING_ORIENTATION_CHANGED =
"Encoding orientation had been changed. Stop streaming first and restart streaming will take effect";
}
================================================
FILE: android/src/main/java/com/pili/rnpili/support/FocusIndicatorRotateLayout.java
================================================
//package com.pili.rnpili.support;
//
//import android.annotation.TargetApi;
//import android.content.Context;
//import android.os.Build;
//import android.util.AttributeSet;
//import android.util.Log;
//
//import com.pili.rnpili.R;
//import com.qiniu.pili.droid.streaming.ui.FocusIndicator;
//
//// A view that indicates the focus area or the metering area.
//public class FocusIndicatorRotateLayout extends RotateLayout implements FocusIndicator {
// private static final String TAG = "FocusIndicatorLayout";
//
// // Sometimes continuous autofucus starts and stops several times quickly.
// // These states are used to make sure the animation is run for at least some
// // time.
// private int mState;
// private static final int STATE_IDLE = 0;
// private static final int STATE_FOCUSING = 1;
// private static final int STATE_FINISHING = 2;
//
// private Runnable mDisappear = new Disappear();
// private Runnable mEndAction = new EndAction();
//
// private static final int SCALING_UP_TIME = 1000;
// private static final int SCALING_DOWN_TIME = 200;
// private static final int DISAPPEAR_TIMEOUT = 200;
//
// public FocusIndicatorRotateLayout(Context context, AttributeSet attrs) {
// super(context, attrs);
// }
//
// private void setDrawable(int resid) {
// mChild.setBackgroundDrawable(getResources().getDrawable(resid));
// }
//
// @Override
// @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
// public void showStart() {
// Log.i(TAG, "showStart");
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
// return;
// }
// if (mState == STATE_IDLE) {
// setDrawable(R.drawable.ic_focus_focusing);
// animate().withLayer().setDuration(SCALING_UP_TIME)
// .scaleX(1.5f).scaleY(1.5f);
// mState = STATE_FOCUSING;
// }
// }
//
// @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
// @Override
// public void showSuccess(boolean timeout) {
// Log.i(TAG, "showSuccess");
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
// return;
// }
// if (mState == STATE_FOCUSING) {
// setDrawable(R.drawable.ic_focus_focused);
// animate().withLayer().setDuration(SCALING_DOWN_TIME).scaleX(1f)
// .scaleY(1f).withEndAction(timeout ? mEndAction : null);
// mState = STATE_FINISHING;
// }
// }
//
// @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
// @Override
// public void showFail(boolean timeout) {
// Log.i(TAG, "showFail");
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
// return;
// }
// if (mState == STATE_FOCUSING) {
// setDrawable(R.drawable.ic_focus_failed);
// animate().withLayer().setDuration(SCALING_DOWN_TIME).scaleX(1f)
// .scaleY(1f).withEndAction(timeout ? mEndAction : null);
// mState = STATE_FINISHING;
// }
// }
//
// @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
// @Override
// public void clear() {
// Log.i(TAG, "clear");
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
// return;
// }
// animate().cancel();
// removeCallbacks(mDisappear);
// mDisappear.run();
// setScaleX(1f);
// setScaleY(1f);
// }
//
// private class EndAction implements Runnable {
// @Override
// public void run() {
// // Keep the focus indicator for some time.
// postDelayed(mDisappear, DISAPPEAR_TIMEOUT);
// }
// }
//
// private class Disappear implements Runnable {
// @Override
// public void run() {
// mChild.setBackgroundDrawable(null);
// mState = STATE_IDLE;
// }
// }
//}
================================================
FILE: android/src/main/java/com/pili/rnpili/support/Jsons.java
================================================
package com.pili.rnpili.support;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.ReadableType;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Created by buhe on 16/5/5.
*/
public class Jsons {
public static JSONObject readableMapToJson(ReadableMap readableMap) {
JSONObject jsonObject = new JSONObject();
if (readableMap == null) {
return null;
}
ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
if (!iterator.hasNextKey()) {
return null;
}
while (iterator.hasNextKey()) {
String key = iterator.nextKey();
ReadableType readableType = readableMap.getType(key);
try {
switch (readableType) {
case Null:
jsonObject.put(key, null);
break;
case Boolean:
jsonObject.put(key, readableMap.getBoolean(key));
break;
case Number:
// Can be int or double.
jsonObject.put(key, readableMap.getInt(key));
break;
case String:
jsonObject.put(key, readableMap.getString(key));
break;
case Map:
jsonObject.put(key, readableMapToJson(readableMap.getMap(key)));
break;
case Array:
jsonObject.put(key, readableMap.getArray(key));
default:
// Do nothing and fail silently
}
} catch (JSONException ex) {
// Do nothing and fail silently
}
}
return jsonObject;
}
}
================================================
FILE: android/src/main/java/com/pili/rnpili/support/MediaController.java
================================================
//package com.pili.rnpili.support;
//
//import android.annotation.SuppressLint;
//import android.content.Context;
//import android.content.res.Resources;
//import android.graphics.Rect;
//import android.media.AudioManager;
//import android.os.Build;
//import android.os.Handler;
//import android.os.Message;
//import android.util.AttributeSet;
//import android.util.Log;
//import android.view.Gravity;
//import android.view.KeyEvent;
//import android.view.LayoutInflater;
//import android.view.MotionEvent;
//import android.view.View;
//import android.widget.FrameLayout;
//import android.widget.ImageButton;
//import android.widget.PopupWindow;
//import android.widget.ProgressBar;
//import android.widget.SeekBar;
//import android.widget.TextView;
//
//import com.pili.pldroid.player.IMediaController;
//
//import java.util.Locale;
//
///**
// * You can write a custom MediaController instead of this class
// * A MediaController widget must implement all the interface defined by com.pili.pldroid.player.IMediaController
// */
//public class MediaController extends FrameLayout implements IMediaController {
//
// private static final String TAG = "PLMediaController";
// private IMediaController.MediaPlayerControl mPlayer;
// private Context mContext;
// private PopupWindow mWindow;
// private int mAnimStyle;
// private View mAnchor;
// private View mRoot;
// private ProgressBar mProgress;
// private TextView mEndTime, mCurrentTime;
// private long mDuration;
// private boolean mShowing;
// private boolean mDragging;
// private boolean mInstantSeeking = true;
// private static int sDefaultTimeout = 3000;
// private static final int SEEK_TO_POST_DELAY_MILLIS = 200;
//
// private static final int FADE_OUT = 1;
// private static final int SHOW_PROGRESS = 2;
// private boolean mFromXml = false;
// private ImageButton mPauseButton;
// private ImageButton mFfwdButton;
// private ImageButton mRewButton;
// private ImageButton mNextButton;
// private ImageButton mPrevButton;
//
// private boolean mUseFastForward;
//
// private static final int IC_MEDIA_PAUSE_ID = Resources.getSystem().getIdentifier("ic_media_pause","drawable", "android");
// private static final int IC_MEDIA_PLAY_ID = Resources.getSystem().getIdentifier("ic_media_play","drawable", "android");
// private static final int MEDIA_CONTROLLER_ID = Resources.getSystem().getIdentifier("media_controller", "layout", "android");
// private static final int PRV_BUTTON_ID = Resources.getSystem().getIdentifier("prev","id", "android");
// private static final int FFWD_BUTTON_ID = Resources.getSystem().getIdentifier("ffwd","id", "android");
// private static final int NEXT_BUTTON_ID = Resources.getSystem().getIdentifier("next","id", "android");
// private static final int REW_BUTTON_ID = Resources.getSystem().getIdentifier("rew","id", "android");
// private static final int PAUSE_BUTTON_ID = Resources.getSystem().getIdentifier("pause","id", "android");
// private static final int MEDIACONTROLLER_PROGRESS_ID = Resources.getSystem().getIdentifier("mediacontroller_progress","id", "android");
// private static final int END_TIME_ID = Resources.getSystem().getIdentifier("time","id", "android");
// private static final int CURRENT_TIME_ID = Resources.getSystem().getIdentifier("time_current","id", "android");
//
// private AudioManager mAM;
// private Runnable mLastSeekBarRunnable;
// private boolean mDisableProgress = false;
//
// public MediaController(Context context, AttributeSet attrs) {
// super(context, attrs);
// mRoot = this;
// mFromXml = true;
// initController(context);
// }
//
// public MediaController(Context context) {
// super(context);
// if (!mFromXml && initController(context))
// initFloatingWindow();
// }
//
// public MediaController(Context context, boolean useFastForward, boolean disableProgressBar) {
// this(context);
// mUseFastForward = useFastForward;
// mDisableProgress = disableProgressBar;
// }
//
// public MediaController(Context context, boolean useFastForward) {
// this(context);
// mUseFastForward = useFastForward;
// }
//
// private boolean initController(Context context) {
// mUseFastForward = true;
// mContext = context;
// mAM = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
// return true;
// }
//
// @Override
// public void onFinishInflate() {
// if (mRoot != null)
// initControllerView(mRoot);
// super.onFinishInflate();
// }
//
// private void initFloatingWindow() {
// mWindow = new PopupWindow(mContext);
// mWindow.setFocusable(false);
// mWindow.setBackgroundDrawable(null);
// mWindow.setOutsideTouchable(true);
// mAnimStyle = android.R.style.Animation;
// }
//
// /**
// * Create the view that holds the widgets that control playback. Derived
// * classes can override this to create their own.
// *
// * @return The controller view.
// */
// protected View makeControllerView() {
// return ((LayoutInflater) mContext
// .getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(MEDIA_CONTROLLER_ID, this);
// }
//
// private void initControllerView(View v) {
// // By default these are hidden.
// mPrevButton = (ImageButton) v.findViewById(PRV_BUTTON_ID);
// if (mPrevButton != null) {
// mPrevButton.setVisibility(View.GONE);
// }
// mNextButton = (ImageButton) v.findViewById(NEXT_BUTTON_ID);
// if (mNextButton != null) {
// mNextButton.setVisibility(View.GONE);
// }
//
// mFfwdButton = (ImageButton) v.findViewById(FFWD_BUTTON_ID);
// if (mFfwdButton != null) {
// mFfwdButton.setOnClickListener(mFfwdListener);
// if (!mFromXml) {
// mFfwdButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
// }
// }
//
// mRewButton = (ImageButton) v.findViewById(REW_BUTTON_ID);
// if (mRewButton != null) {
// mRewButton.setOnClickListener(mRewListener);
// if (!mFromXml) {
// mRewButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
// }
// }
// mPauseButton = (ImageButton) v.findViewById(PAUSE_BUTTON_ID);
// if (mPauseButton != null) {
// mPauseButton.requestFocus();
// mPauseButton.setOnClickListener(mPauseListener);
// }
//
// mProgress = (ProgressBar) v.findViewById(MEDIACONTROLLER_PROGRESS_ID);
// if (mProgress != null) {
// if (mProgress instanceof SeekBar) {
// SeekBar seeker = (SeekBar) mProgress;
// seeker.setOnSeekBarChangeListener(mSeekListener);
// seeker.setThumbOffset(1);
// }
// mProgress.setMax(1000);
// mProgress.setEnabled(!mDisableProgress);
// }
//
// mEndTime = (TextView) v.findViewById(END_TIME_ID);
// mCurrentTime = (TextView) v.findViewById(CURRENT_TIME_ID);
// }
//
// /**
// * Control the action when the seekbar dragged by user
// *
// * @param seekWhenDragging
// * True the media will seek periodically
// */
// public void setInstantSeeking(boolean seekWhenDragging) {
// mInstantSeeking = seekWhenDragging;
// }
//
// private void disableUnsupportedButtons() {
// try {
// if (mPauseButton != null && !mPlayer.canPause())
// mPauseButton.setEnabled(false);
// } catch (IncompatibleClassChangeError ex) {
// }
// }
//
// /**
// *
// * Change the animation style resource for this controller.
// *
// *
// *
// * If the controller is showing, calling this method will take effect only
// * the next time the controller is shown.
// *
// *
// * @param animationStyle
// * animation style to use when the controller appears and disappears.
// * Set to -1 for the default animation, 0 for no animation,
// * or a resource identifier for an explicit animation.
// *
// */
// public void setAnimationStyle(int animationStyle) {
// mAnimStyle = animationStyle;
// }
//
// public interface OnShownListener {
// public void onShown();
// }
//
// private OnShownListener mShownListener;
//
// public void setOnShownListener(OnShownListener l) {
// mShownListener = l;
// }
//
// public interface OnHiddenListener {
// public void onHidden();
// }
//
// private OnHiddenListener mHiddenListener;
//
// public void setOnHiddenListener(OnHiddenListener l) {
// mHiddenListener = l;
// }
//
// @SuppressLint("HandlerLeak")
// private Handler mHandler = new Handler() {
// @Override
// public void handleMessage(Message msg) {
// long pos;
// switch (msg.what) {
// case FADE_OUT:
// hide();
// break;
// case SHOW_PROGRESS:
// pos = setProgress();
// if (!mDragging && mShowing) {
// msg = obtainMessage(SHOW_PROGRESS);
// sendMessageDelayed(msg, 1000 - (pos % 1000));
// updatePausePlay();
// }
// break;
// }
// }
// };
//
// private long setProgress() {
// if (mPlayer == null || mDragging)
// return 0;
//
// long position = mPlayer.getCurrentPosition();
// long duration = mPlayer.getDuration();
// if (mProgress != null) {
// if (duration > 0) {
// long pos = 1000L * position / duration;
// mProgress.setProgress((int) pos);
// }
// int percent = mPlayer.getBufferPercentage();
// mProgress.setSecondaryProgress(percent * 10);
// }
//
// mDuration = duration;
//
// if (mEndTime != null)
// mEndTime.setText(generateTime(mDuration));
// if (mCurrentTime != null)
// mCurrentTime.setText(generateTime(position));
//
// return position;
// }
//
// private static String generateTime(long position) {
// int totalSeconds = (int) (position / 1000);
//
// int seconds = totalSeconds % 60;
// int minutes = (totalSeconds / 60) % 60;
// int hours = totalSeconds / 3600;
//
// if (hours > 0) {
// return String.format(Locale.US, "%02d:%02d:%02d", hours, minutes,
// seconds).toString();
// } else {
// return String.format(Locale.US, "%02d:%02d", minutes, seconds)
// .toString();
// }
// }
//
// @Override
// public boolean onTouchEvent(MotionEvent event) {
// show(sDefaultTimeout);
// return true;
// }
//
// @Override
// public boolean onTrackballEvent(MotionEvent ev) {
// show(sDefaultTimeout);
// return false;
// }
//
// @Override
// public boolean dispatchKeyEvent(KeyEvent event) {
// int keyCode = event.getKeyCode();
// if (event.getRepeatCount() == 0
// && (keyCode == KeyEvent.KEYCODE_HEADSETHOOK
// || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || keyCode == KeyEvent.KEYCODE_SPACE)) {
// doPauseResume();
// show(sDefaultTimeout);
// if (mPauseButton != null)
// mPauseButton.requestFocus();
// return true;
// } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
// if (mPlayer.isPlaying()) {
// mPlayer.pause();
// updatePausePlay();
// }
// return true;
// } else if (keyCode == KeyEvent.KEYCODE_BACK
// || keyCode == KeyEvent.KEYCODE_MENU) {
// hide();
// return true;
// } else {
// show(sDefaultTimeout);
// }
// return super.dispatchKeyEvent(event);
// }
//
// private OnClickListener mPauseListener = new OnClickListener() {
// public void onClick(View v) {
// doPauseResume();
// show(sDefaultTimeout);
// }
// };
//
// private void updatePausePlay() {
// if (mRoot == null || mPauseButton == null)
// return;
//
// if (mPlayer.isPlaying())
// mPauseButton.setImageResource(IC_MEDIA_PAUSE_ID);
// else
// mPauseButton.setImageResource(IC_MEDIA_PLAY_ID);
// }
//
// private void doPauseResume() {
// if (mPlayer.isPlaying())
// mPlayer.pause();
// else
// mPlayer.start();
// updatePausePlay();
// }
//
// private SeekBar.OnSeekBarChangeListener mSeekListener = new SeekBar.OnSeekBarChangeListener() {
//
// public void onStartTrackingTouch(SeekBar bar) {
// mDragging = true;
// show(3600000);
// mHandler.removeMessages(SHOW_PROGRESS);
// if (mInstantSeeking)
// mAM.setStreamMute(AudioManager.STREAM_MUSIC, true);
// }
//
// public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
// if (!fromuser)
// return;
//
// final int newposition = (int) (mDuration * progress) / 1000;
// String time = generateTime(newposition);
// if (mInstantSeeking) {
// mHandler.removeCallbacks(mLastSeekBarRunnable);
// mLastSeekBarRunnable = new Runnable() {
// @Override
// public void run() {
// mPlayer.seekTo(newposition);
// }
// };
// mHandler.postDelayed(mLastSeekBarRunnable, SEEK_TO_POST_DELAY_MILLIS);
// }
// if (mCurrentTime != null)
// mCurrentTime.setText(time);
// }
//
// public void onStopTrackingTouch(SeekBar bar) {
// if (!mInstantSeeking)
// mPlayer.seekTo((int)(mDuration * bar.getProgress()) / 1000);
//
// show(sDefaultTimeout);
// mHandler.removeMessages(SHOW_PROGRESS);
// mAM.setStreamMute(AudioManager.STREAM_MUSIC, false);
// mDragging = false;
// mHandler.sendEmptyMessageDelayed(SHOW_PROGRESS, 1000);
// }
// };
//
// private OnClickListener mRewListener = new OnClickListener() {
// public void onClick(View v) {
// int pos = (int)mPlayer.getCurrentPosition();
// pos -= 5000; // milliseconds
// mPlayer.seekTo(pos);
// setProgress();
//
// show(sDefaultTimeout);
// }
// };
//
// private OnClickListener mFfwdListener = new OnClickListener() {
// public void onClick(View v) {
// int pos = (int)mPlayer.getCurrentPosition();
// pos += 15000; // milliseconds
// mPlayer.seekTo(pos);
// setProgress();
//
// show(sDefaultTimeout);
// }
// };
//
// /**
// * Set the view that acts as the anchor for the control view.
// *
// * - This can for example be a VideoView, or your Activity's main view.
// * - AudioPlayer has no anchor view, so the view parameter will be null.
// *
// * @param view
// * The view to which to anchor the controller when it is visible.
// */
// @Override
// public void setAnchorView(View view) {
// mAnchor = view;
// if (mAnchor == null) {
// sDefaultTimeout = 0; // show forever
// }
// if (!mFromXml) {
// removeAllViews();
// mRoot = makeControllerView();
// mWindow.setContentView(mRoot);
// mWindow.setWidth(LayoutParams.MATCH_PARENT);
// mWindow.setHeight(LayoutParams.WRAP_CONTENT);
// }
// initControllerView(mRoot);
// }
//
// @Override
// public void setMediaPlayer(MediaPlayerControl player) {
// mPlayer = player;
// updatePausePlay();
// }
//
// @Override
// public void show() {
// show(sDefaultTimeout);
// }
//
// /**
// * Show the controller on screen. It will go away automatically after
// * 'timeout' milliseconds of inactivity.
// *
// * @param timeout
// * The timeout in milliseconds. Use 0 to show the controller until hide() is called.
// */
// @Override
// public void show(int timeout) {
// if (!mShowing) {
// if (mAnchor != null && mAnchor.getWindowToken() != null) {
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// mAnchor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
// }
// }
// if (mPauseButton != null)
// mPauseButton.requestFocus();
// disableUnsupportedButtons();
//
// if (mFromXml) {
// setVisibility(View.VISIBLE);
// } else {
// int[] location = new int[2];
//
// if (mAnchor != null) {
// mAnchor.getLocationOnScreen(location);
// Rect anchorRect = new Rect(location[0], location[1],
// location[0] + mAnchor.getWidth(), location[1]
// + mAnchor.getHeight());
//
// mWindow.setAnimationStyle(mAnimStyle);
// mWindow.showAtLocation(mAnchor, Gravity.BOTTOM,
// anchorRect.left, 0);
// } else {
// Rect anchorRect = new Rect(location[0], location[1],
// location[0] + mRoot.getWidth(), location[1]
// + mRoot.getHeight());
//
// mWindow.setAnimationStyle(mAnimStyle);
// mWindow.showAtLocation(mRoot, Gravity.BOTTOM,
// anchorRect.left, 0);
// }
// }
// mShowing = true;
// if (mShownListener != null)
// mShownListener.onShown();
// }
// updatePausePlay();
// mHandler.sendEmptyMessage(SHOW_PROGRESS);
//
// if (timeout != 0) {
// mHandler.removeMessages(FADE_OUT);
// mHandler.sendMessageDelayed(mHandler.obtainMessage(FADE_OUT),
// timeout);
// }
// }
//
// @Override
// public boolean isShowing() {
// return mShowing;
// }
//
// @Override
// public void hide() {
// if (mShowing) {
// if (mAnchor != null) {
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// //mAnchor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
// }
// }
// try {
// mHandler.removeMessages(SHOW_PROGRESS);
// if (mFromXml)
// setVisibility(View.GONE);
// else
// mWindow.dismiss();
// } catch (IllegalArgumentException ex) {
// Log.d(TAG, "MediaController already removed");
// }
// mShowing = false;
// if (mHiddenListener != null)
// mHiddenListener.onHidden();
// }
// }
//
// @Override
// public void setEnabled(boolean enabled) {
// if (mPauseButton != null) {
// mPauseButton.setEnabled(enabled);
// }
// if (mFfwdButton != null) {
// mFfwdButton.setEnabled(enabled);
// }
// if (mRewButton != null) {
// mRewButton.setEnabled(enabled);
// }
// if (mProgress != null && !mDisableProgress)
// mProgress.setEnabled(enabled);
// disableUnsupportedButtons();
// super.setEnabled(enabled);
// }
//}
================================================
FILE: android/src/main/java/com/pili/rnpili/support/Rotatable.java
================================================
package com.pili.rnpili.support;
/**
* Created by jerikc on 16/2/5.
*/
public interface Rotatable {
// Set parameter 'animation' to true to have animation when rotation.
void setOrientation(int orientation, boolean animation);
}
================================================
FILE: android/src/main/java/com/pili/rnpili/support/RotateLayout.java
================================================
package com.pili.rnpili.support;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
// A RotateLayout is designed to display a single item and provides the
// capabilities to rotate the item.
public class RotateLayout extends ViewGroup implements Rotatable {
@SuppressWarnings("unused")
private static final String TAG = "RotateLayout";
private int mOrientation;
protected View mChild;
public RotateLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// The transparent background here is a workaround of the render issue
// happened when the view is rotated as the device's orientation
// changed. The view looks fine in landscape. After rotation, the view
// is invisible.
setBackgroundResource(android.R.color.transparent);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mChild = getChildAt(0);
mChild.setPivotX(0);
mChild.setPivotY(0);
}
public void setChild(View mChild) {
this.mChild = mChild;
}
@Override
protected void onLayout(
boolean change, int left, int top, int right, int bottom) {
int width = right - left;
int height = bottom - top;
switch (mOrientation) {
case 0:
case 180:
mChild.layout(0, 0, width, height);
break;
case 90:
case 270:
mChild.layout(0, 0, height, width);
break;
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
int w = 0, h = 0;
switch(mOrientation) {
case 0:
case 180:
measureChild(mChild, widthSpec, heightSpec);
w = mChild.getMeasuredWidth();
h = mChild.getMeasuredHeight();
break;
case 90:
case 270:
measureChild(mChild, heightSpec, widthSpec);
w = mChild.getMeasuredHeight();
h = mChild.getMeasuredWidth();
break;
}
setMeasuredDimension(w, h);
switch (mOrientation) {
case 0:
mChild.setTranslationX(0);
mChild.setTranslationY(0);
break;
case 90:
mChild.setTranslationX(0);
mChild.setTranslationY(h);
break;
case 180:
mChild.setTranslationX(w);
mChild.setTranslationY(h);
break;
case 270:
mChild.setTranslationX(w);
mChild.setTranslationY(0);
break;
}
mChild.setRotation(-mOrientation);
}
@Override
public boolean shouldDelayChildPressedState() {
return false;
}
// Rotate the view counter-clockwise
@Override
public void setOrientation(int orientation, boolean animation) {
orientation = orientation % 360;
if (mOrientation == orientation) return;
mOrientation = orientation;
requestLayout();
}
}
================================================
FILE: android/src/test/java/com/pili/rnpili/ExampleUnitTest.java
================================================
package com.pili.rnpili;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* To work on unit tests, switch the Test Artifact in the Build Variants view.
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
================================================
FILE: index.js
================================================
/**
* Created by buhe on 16/4/28.
*/
module.exports = {
Streaming: require('./Streaming'),
AudioStreaming: require('./AudioStreaming'),
Player: require('./Player'),
StreamingConst: require('./StreamingConst')
};
================================================
FILE: ios/RCTPili/RCTPili/Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
FMWK
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
NSPrincipalClass
================================================
FILE: ios/RCTPili/RCTPili/RCTAudioStreaming.h
================================================
//
// RCTStreaming.h
// RCTPili
//
// Created by guguyanhua on 16/5/26.
// Copyright © 2016年 pili. All rights reserved.
//
#import
#import "RCTView.h"
#import "PLCameraStreamingKit.h"
#import "Reachability.h"
#import
@class RCTEventDispatcher;
@interface RCTAudioStreaming : UIView
@property (nonatomic, strong) PLCameraStreamingSession *session;
@property (nonatomic, strong) dispatch_queue_t sessionQueue;
@property (nonatomic, strong) Reachability *internetReachability;
@property (nonatomic, strong) NSDictionary *profile;
@property (nonatomic, strong) NSString *rtmpURL;
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
@end
================================================
FILE: ios/RCTPili/RCTPili/RCTAudioStreaming.m
================================================
//
// RCTStreaming.m
// RCTPili
//
// Created by guguyanhua on 16/5/26.
// Copyright © 2016年 pili. All rights reserved.
//
#import "RCTAudioStreaming.h"
#import "RCTBridgeModule.h"
#import "UIView+React.h"
#import "RCTEventDispatcher.h"
@implementation RCTAudioStreaming{
RCTEventDispatcher *_eventDispatcher;
BOOL _started;
BOOL _muted;
}
const char *audioStateNames[] = {
"Unknow",
"Connecting",
"Connected",
"Disconnecting",
"Disconnected",
"Error"
};
const char *audioNetworkStatus[] = {
"Not Reachable",
"Reachable via WiFi",
"Reachable via CELL"
};
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
{
if ((self = [super init])) {
[PLStreamingEnv initEnv];
_eventDispatcher = eventDispatcher;
_started = YES;
_muted = NO;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil];
self.internetReachability = [Reachability reachabilityForInternetConnection];
[self.internetReachability startNotifier];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleInterruption:)
name:AVAudioSessionInterruptionNotification
object:[AVAudioSession sharedInstance]];
CGSize videoSize = CGSizeMake(480 , 640);
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation <= AVCaptureVideoOrientationLandscapeLeft) {
if (orientation > AVCaptureVideoOrientationPortraitUpsideDown) {
videoSize = CGSizeMake(640 , 480);
}
}
self.sessionQueue = dispatch_queue_create("pili.queue.streaming", DISPATCH_QUEUE_SERIAL);
}
return self;
};
- (void) setRtmpURL:(NSString *)rtmpURL
{
_rtmpURL = rtmpURL;
[self setSourceAndProfile];
}
- (void)setProfile:(NSDictionary *)profile{
_profile = profile;
[self setSourceAndProfile];
}
- (void) setSourceAndProfile{
if(self.profile && self.rtmpURL){
void (^permissionBlock)(void) = ^{
dispatch_async(self.sessionQueue, ^{
NSDictionary *audio = self.profile[@"audio"];
PLAudioCaptureConfiguration *audioCaptureConfiguration = [PLAudioCaptureConfiguration defaultConfiguration];
// 音频编码配置
PLAudioStreamingConfiguration *audioStreamingConfiguration = [PLAudioStreamingConfiguration defaultConfiguration];
AVCaptureVideoOrientation orientation = (AVCaptureVideoOrientation)(([[UIDevice currentDevice] orientation] <= UIDeviceOrientationLandscapeRight && [[UIDevice currentDevice] orientation] != UIDeviceOrientationUnknown) ? [[UIDevice currentDevice] orientation]: UIDeviceOrientationPortrait);
// 推流 session
self.session = [[PLCameraStreamingSession alloc] initWithVideoCaptureConfiguration:nil audioCaptureConfiguration:audioCaptureConfiguration videoStreamingConfiguration:nil audioStreamingConfiguration:audioStreamingConfiguration stream:nil videoOrientation:orientation];
self.session.delegate = self;
dispatch_async(dispatch_get_main_queue(), ^{
if(_muted){
[self setMuted:_muted];
}
[self startSession];
});
});
};
void (^noAccessBlock)(void) = ^{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"No Access", nil)
message:NSLocalizedString(@"!", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Cancel", nil)
otherButtonTitles:nil];
[alertView show];
};
switch ([PLCameraStreamingSession cameraAuthorizationStatus]) {
case PLAuthorizationStatusAuthorized:
permissionBlock();
break;
case PLAuthorizationStatusNotDetermined: {
[PLCameraStreamingSession requestCameraAccessWithCompletionHandler:^(BOOL granted) {
granted ? permissionBlock() : noAccessBlock();
}];
}
break;
default:
noAccessBlock();
break;
}
}
}
- (void)setStarted:(BOOL) started {
if(started != _started){
if(started){
[self startSession];
_started = started;
}else{
[self stopSession];
_started = started;
}
}
}
-(void)setMuted:(BOOL) muted {
_muted = muted;
[self.session setMuted:muted];
}
- (void)streamingSessionSendingBufferDidFull:(id)session {
NSString *log = @"Buffer is full";
NSLog(@"%@", log);
}
- (void)streamingSession:(id)session sendingBufferDidDropItems:(NSArray *)items {
NSString *log = @"Frame dropped";
NSLog(@"%@", log);
}
- (void)stopSession {
dispatch_async(self.sessionQueue, ^{
[self.session stop];
});
}
- (void)startSession {
dispatch_async(self.sessionQueue, ^{
NSURL *streamURL = [NSURL URLWithString:self.rtmpURL];
[self.session startWithPushURL:streamURL feedback:^(PLStreamStartStateFeedback feedback) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"success ");
});
}];
});
}
- (void)cameraStreamingSession:(PLCameraStreamingSession *)session streamStatusDidUpdate:(PLStreamStatus *)status {
NSString *log = [NSString stringWithFormat:@"Stream Status: %@", status];
NSLog(@"%@", log);
}
- (void)cameraStreamingSession:(PLCameraStreamingSession *)session streamStateDidChange:(PLStreamState)state {
NSString *log = [NSString stringWithFormat:@"Stream State: %s", audioStateNames[state]];
NSLog(@"%@", log);
switch (state) {
case PLStreamStateUnknow:
[_eventDispatcher sendInputEventWithName:@"onLoading" body:@{@"target": self.reactTag}];
break;
case PLStreamStateConnecting:
[_eventDispatcher sendInputEventWithName:@"onConnecting" body:@{@"target": self.reactTag}];
break;
case PLStreamStateConnected:
[_eventDispatcher sendInputEventWithName:@"onStreaming" body:@{@"target": self.reactTag}];
break;
case PLStreamStateDisconnecting:
break;
case PLStreamStateDisconnected:
[_eventDispatcher sendInputEventWithName:@"onDisconnected" body:@{@"target": self.reactTag}];
[_eventDispatcher sendInputEventWithName:@"onShutdown" body:@{@"target": self.reactTag}]; //FIXME
break;
case PLStreamStateError:
[_eventDispatcher sendInputEventWithName:@"onIOError" body:@{@"target": self.reactTag}];
break;
default:
break;
}
}
- (void)cameraStreamingSession:(PLCameraStreamingSession *)session didDisconnectWithError:(NSError *)error {
NSString *log = [NSString stringWithFormat:@"Stream State: Error. %@", error];
NSLog(@"%@", log);
[self startSession];
}
- (void)reachabilityChanged:(NSNotification *)notif{
Reachability *curReach = [notif object];
NSParameterAssert([curReach isKindOfClass:[Reachability class]]);
NetworkStatus status = [curReach currentReachabilityStatus];
if (NotReachable == status) {
// 对断网情况做处理
[self stopSession];
}
NSString *log = [NSString stringWithFormat:@"Networkt Status: %s", audioNetworkStatus[status]];
NSLog(@"%@", log);
}
- (void)handleInterruption:(NSNotification *)notification {
if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification]) {
NSLog(@"Interruption notification");
if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeBegan]]) {
NSLog(@"InterruptionTypeBegan");
} else {
// the facetime iOS 9 has a bug: 1 does not send interrupt end 2 you can use application become active, and repeat set audio session acitve until success. ref http://blog.corywiles.com/broken-facetime-audio-interruptions-in-ios-9
NSLog(@"InterruptionTypeEnded");
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];
}
}
}
@end
================================================
FILE: ios/RCTPili/RCTPili/RCTAudioStreamingManager.h
================================================
//
// RCTStreamingManager.h
// RCTPili
//
// Created by guguyanhua on 16/5/26.
// Copyright © 2016年 pili. All rights reserved.
//
#import "RCTViewManager.h"
@interface RCTAudioStreamingManager : RCTViewManager
@end
================================================
FILE: ios/RCTPili/RCTPili/RCTAudioStreamingManager.m
================================================
//
// RCTStreamingManager.m
// RCTPili
//
// Created by guguyanhua on 16/5/26.
// Copyright © 2016年 pili. All rights reserved.
//
#import "RCTAudioStreamingManager.h"
#import "RCTAudioStreaming.h"
@implementation RCTAudioStreamingManager
RCT_EXPORT_MODULE();
@synthesize bridge = _bridge;
- (UIView *)view
{
return [[RCTAudioStreaming alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
}
- (NSArray *)customDirectEventTypes
{
return @[
@"onReady",
@"onConnecting",
@"onStreaming",
@"onShutdown",
@"onIOError",
@"onDisconnected"
];
}
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
RCT_EXPORT_VIEW_PROPERTY(rtmpURL, NSString);
RCT_EXPORT_VIEW_PROPERTY(profile, NSDictionary);
RCT_EXPORT_VIEW_PROPERTY(started, BOOL);
RCT_EXPORT_VIEW_PROPERTY(muted, BOOL);
@end
================================================
FILE: ios/RCTPili/RCTPili/RCTPili.h
================================================
//
// RCTPili.h
// RCTPili
//
// Created by buhe on 16/5/11.
// Copyright © 2016年 pili. All rights reserved.
//
#import
@interface RCTPili : NSObject
@end
================================================
FILE: ios/RCTPili/RCTPili/RCTPili.m
================================================
//
// RCTPili.m
// RCTPili
//
// Created by buhe on 16/5/11.
// Copyright © 2016年 pili. All rights reserved.
//
#import "RCTPili.h"
@implementation RCTPili
@end
================================================
FILE: ios/RCTPili/RCTPili/RCTPlayer.h
================================================
//
// RCTPlayer.h
// RCTPili
//
// Created by buhe on 16/5/12.
// Copyright © 2016年 pili. All rights reserved.
//
#import
#import "RCTView.h"
#import "PLPlayer.h"
@class RCTEventDispatcher;
@interface RCTPlayer : UIView
@property (nonatomic, assign) int reconnectCount;
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
@end
================================================
FILE: ios/RCTPili/RCTPili/RCTPlayer.m
================================================
//
// RCTPlayer.m
// RCTPili
//
// Created by buhe on 16/5/12.
// Copyright © 2016年 pili. All rights reserved.
//
#import "RCTPlayer.h"
#import "RCTBridgeModule.h"
#import "RCTEventDispatcher.h"
#import "UIView+React.h"
@implementation RCTPlayer{
RCTEventDispatcher *_eventDispatcher;
PLPlayer *_plplayer;
bool _started;
bool _muted;
}
static NSString *status[] = {
@"PLPlayerStatusUnknow",
@"PLPlayerStatusPreparing",
@"PLPlayerStatusReady",
@"PLPlayerStatusCaching",
@"PLPlayerStatusPlaying",
@"PLPlayerStatusPaused",
@"PLPlayerStatusStopped",
@"PLPlayerStatusError"
};
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
{
if ((self = [super init])) {
_eventDispatcher = eventDispatcher;
_started = YES;
_muted = NO;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
self.reconnectCount = 0;
}
return self;
};
- (void) setSource:(NSDictionary *)source
{
NSString *uri = source[@"uri"];
bool backgroundPlay = source[@"backgroundPlay"] == nil ? false : source[@"backgroundPlay"];
PLPlayerOption *option = [PLPlayerOption defaultOption];
// 更改需要修改的 option 属性键所对应的值
[option setOptionValue:@15 forKey:PLPlayerOptionKeyTimeoutIntervalForMediaPackets];
if(_plplayer){
[_plplayer stop]; //TODO View 被卸载时 也要调用
}
_plplayer = [PLPlayer playerWithURL:[[NSURL alloc] initWithString:uri] option:option];
_plplayer.delegate = self;
_plplayer.delegateQueue = dispatch_get_main_queue();
_plplayer.backgroundPlayEnable = backgroundPlay;
if(backgroundPlay){
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(startPlayer) name:UIApplicationWillEnterForegroundNotification object:nil];
}
[self setupUI];
[self startPlayer];
}
- (void)setupUI {
if (_plplayer.status != PLPlayerStatusError) {
// add player view
UIView *playerView = _plplayer.playerView;
[self addSubview:playerView];
[playerView setTranslatesAutoresizingMaskIntoConstraints:NO];
NSLayoutConstraint *centerX = [NSLayoutConstraint constraintWithItem:playerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0];
NSLayoutConstraint *centerY = [NSLayoutConstraint constraintWithItem:playerView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0];
NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:playerView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0];
NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:playerView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0];
NSArray *constraints = [NSArray arrayWithObjects:centerX, centerY,width,height, nil];
[self addConstraints: constraints];
}
}
- (void) setStarted:(BOOL) started{
if(started != _started){
if(started){
[_plplayer resume];
_started = started;
}else{
[_plplayer pause];
_started = started;
}
}
}
- (void) setMuted:(BOOL) muted {
_muted = muted;
[_plplayer setMute:muted];
}
- (void)startPlayer {
[UIApplication sharedApplication].idleTimerDisabled = YES;
[_plplayer play];
_started = true;
}
#pragma mark -
- (void)player:(nonnull PLPlayer *)player statusDidChange:(PLPlayerStatus)state {
switch (state) {
case PLPlayerStatusCaching:
[_eventDispatcher sendInputEventWithName:@"onLoading" body:@{@"target": self.reactTag}];
break;
case PLPlayerStatusPlaying:
[_eventDispatcher sendInputEventWithName:@"onPlaying" body:@{@"target": self.reactTag}];
break;
case PLPlayerStatusPaused:
[_eventDispatcher sendInputEventWithName:@"onPaused" body:@{@"target": self.reactTag}];
break;
case PLPlayerStatusStopped:
[_eventDispatcher sendInputEventWithName:@"onShutdown" body:@{@"target": self.reactTag}];
break;
case PLPlayerStatusError:
[_eventDispatcher sendInputEventWithName:@"onError" body:@{@"target": self.reactTag , @"errorCode": [NSNumber numberWithUnsignedInt:0]}];
break;
default:
break;
}
NSLog(@"%@", status[state]);
}
- (void)player:(nonnull PLPlayer *)player stoppedWithError:(nullable NSError *)error {
[self tryReconnect:error];
}
- (void)tryReconnect:(nullable NSError *)error {
if (self.reconnectCount < 3) {
_reconnectCount ++;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"错误" message:[NSString stringWithFormat:@"错误 %@,播放器将在%.1f秒后进行第 %d 次重连", error.localizedDescription,0.5 * pow(2, self.reconnectCount - 1), _reconnectCount] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * pow(2, self.reconnectCount) * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[_plplayer play];
});
}else {
[UIApplication sharedApplication].idleTimerDisabled = NO;
NSLog(@"%@", error);
}
}
@end
================================================
FILE: ios/RCTPili/RCTPili/RCTPlayerManager.h
================================================
//
// RCTPlayerManger.h
// RCTPili
//
// Created by buhe on 16/5/12.
// Copyright © 2016年 pili. All rights reserved.
//
#import
#import "RCTViewManager.h"
@interface RCTPlayerManager : RCTViewManager
@end
================================================
FILE: ios/RCTPili/RCTPili/RCTPlayerManager.m
================================================
//
// RCTPlayerManger.m
// RCTPili
//
// Created by buhe on 16/5/12.
// Copyright © 2016年 pili. All rights reserved.
//
#import "RCTPlayerManager.h"
#import "RCTPlayer.h"
@implementation RCTPlayerManager
RCT_EXPORT_MODULE();
@synthesize bridge = _bridge;
- (UIView *)view
{
return [[RCTPlayer alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
}
- (NSArray *)customDirectEventTypes
{
return @[
@"onLoading",
@"onPaused",
@"onShutdown",
@"onError",
@"onPlaying"
];
}
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
RCT_EXPORT_VIEW_PROPERTY(source, NSDictionary);
RCT_EXPORT_VIEW_PROPERTY(started, BOOL);
RCT_EXPORT_VIEW_PROPERTY(muted, BOOL);
@end
================================================
FILE: ios/RCTPili/RCTPili/RCTStreaming.h
================================================
//
// RCTStreaming.h
// RCTPili
//
// Created by guguyanhua on 16/5/26.
// Copyright © 2016年 pili. All rights reserved.
//
#import
#import "RCTView.h"
#import "PLCameraStreamingKit.h"
#import "Reachability.h"
#import
@class RCTEventDispatcher;
@interface RCTStreaming : UIView
@property (nonatomic, strong) PLCameraStreamingSession *session;
@property (nonatomic, strong) dispatch_queue_t sessionQueue;
@property (nonatomic, strong) Reachability *internetReachability;
@property (nonatomic, strong) NSDictionary *profile;
@property (nonatomic, strong) NSString *rtmpURL;
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
@end
================================================
FILE: ios/RCTPili/RCTPili/RCTStreaming.m
================================================
//
// RCTStreaming.m
// RCTPili
//
// Created by guguyanhua on 16/5/26.
// Copyright © 2016年 pili. All rights reserved.
//
#import "RCTStreaming.h"
#import "RCTBridgeModule.h"
#import "UIView+React.h"
#import "RCTEventDispatcher.h"
@implementation RCTStreaming{
RCTEventDispatcher *_eventDispatcher;
BOOL _started;
BOOL _muted;
BOOL _focus;
NSString *_camera;
}
const char *stateNames[] = {
"Unknow",
"Connecting",
"Connected",
"Disconnecting",
"Disconnected",
"Error"
};
const char *networkStatus[] = {
"Not Reachable",
"Reachable via WiFi",
"Reachable via CELL"
};
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
{
if ((self = [super init])) {
[PLStreamingEnv initEnv];
_eventDispatcher = eventDispatcher;
_started = YES;
_muted = NO;
_focus = NO;
_camera = @"front";
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil];
self.internetReachability = [Reachability reachabilityForInternetConnection];
[self.internetReachability startNotifier];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleInterruption:)
name:AVAudioSessionInterruptionNotification
object:[AVAudioSession sharedInstance]];
CGSize videoSize = CGSizeMake(480 , 640);
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation <= AVCaptureVideoOrientationLandscapeLeft) {
if (orientation > AVCaptureVideoOrientationPortraitUpsideDown) {
videoSize = CGSizeMake(640 , 480);
}
}
self.sessionQueue = dispatch_queue_create("pili.queue.streaming", DISPATCH_QUEUE_SERIAL);
}
return self;
};
- (void) setRtmpURL:(NSString *)rtmpURL
{
_rtmpURL = rtmpURL;
[self setSourceAndProfile];
}
- (void)setProfile:(NSDictionary *)profile{
_profile = profile;
[self setSourceAndProfile];
}
- (void) setSourceAndProfile{
if(self.profile && self.rtmpURL){
void (^permissionBlock)(void) = ^{
dispatch_async(self.sessionQueue, ^{
NSDictionary *video = self.profile[@"video"];
NSDictionary *audio = self.profile[@"audio"];
int *fps = [video[@"fps"] integerValue];
int *bps = [video[@"bps"] integerValue];
int *maxFrameInterval = [video[@"maxFrameInterval"] integerValue];
//TODO
double height = 800;
double width = 640;
//TODO videoProfileLevel 需要通过 分辨率 选择
PLVideoStreamingConfiguration *videoStreamingConfiguration = [[PLVideoStreamingConfiguration alloc] initWithVideoSize:CGSizeMake(width, height) expectedSourceVideoFrameRate:fps videoMaxKeyframeInterval:maxFrameInterval averageVideoBitRate:bps videoProfileLevel:AVVideoProfileLevelH264Baseline31];
PLVideoCaptureConfiguration *videoCaptureConfiguration = [PLVideoCaptureConfiguration defaultConfiguration];
PLAudioCaptureConfiguration *audioCaptureConfiguration = [PLAudioCaptureConfiguration defaultConfiguration];
// 音频编码配置
PLAudioStreamingConfiguration *audioStreamingConfiguration = [PLAudioStreamingConfiguration defaultConfiguration];
AVCaptureVideoOrientation orientation = (AVCaptureVideoOrientation)(([[UIDevice currentDevice] orientation] <= UIDeviceOrientationLandscapeRight && [[UIDevice currentDevice] orientation] != UIDeviceOrientationUnknown) ? [[UIDevice currentDevice] orientation]: UIDeviceOrientationPortrait);
// 推流 session
self.session = [[PLCameraStreamingSession alloc] initWithVideoCaptureConfiguration:videoCaptureConfiguration audioCaptureConfiguration:audioCaptureConfiguration videoStreamingConfiguration:videoStreamingConfiguration audioStreamingConfiguration:audioStreamingConfiguration stream:nil videoOrientation:orientation];
self.session.delegate = self;
// UIImage *waterMark = [UIImage imageNamed:@"qiniu.png"];
// PLFilterHandler handler = [self.session addWaterMark:waterMark origin:CGPointMake(100, 300)];
// self.filterHandlers = [@[handler] mutableCopy];//TODO - 水印暂时注释
dispatch_async(dispatch_get_main_queue(), ^{
UIView *previewView = self.session.previewView;
[self addSubview:previewView];
[previewView setTranslatesAutoresizingMaskIntoConstraints:NO];
NSLayoutConstraint *centerX = [NSLayoutConstraint constraintWithItem:previewView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0];
NSLayoutConstraint *centerY = [NSLayoutConstraint constraintWithItem:previewView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0];
NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:previewView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0];
NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:previewView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0];
NSArray *constraints = [NSArray arrayWithObjects:centerX, centerY,width,height, nil];
[self addConstraints: constraints];
NSString *log = [NSString stringWithFormat:@"Zoom Range: [1..%.0f]", self.session.videoActiveFormat.videoMaxZoomFactor];
NSLog(@"%@", log);
if(_focus){
[self.session setSmoothAutoFocusEnabled:_focus];
[self.session setTouchToFocusEnable:_focus];
}
if(_muted){
[self setMuted:_muted];
}
[self startSession];
});
});
};
void (^noAccessBlock)(void) = ^{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"No Access", nil)
message:NSLocalizedString(@"!", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Cancel", nil)
otherButtonTitles:nil];
[alertView show];
};
switch ([PLCameraStreamingSession cameraAuthorizationStatus]) {
case PLAuthorizationStatusAuthorized:
permissionBlock();
break;
case PLAuthorizationStatusNotDetermined: {
[PLCameraStreamingSession requestCameraAccessWithCompletionHandler:^(BOOL granted) {
granted ? permissionBlock() : noAccessBlock();
}];
}
break;
default:
noAccessBlock();
break;
}
}
}
- (void)setStarted:(BOOL) started {
if(started != _started){
if(started){
[self startSession];
_started = started;
}else{
[self stopSession];
_started = started;
}
}
}
-(void)setMuted:(BOOL) muted {
_muted = muted;
[self.session setMuted:muted];
}
-(void)setFocus:(BOOL) focus {
_focus = focus;
[self.session setSmoothAutoFocusEnabled:focus];
[self.session setTouchToFocusEnable:focus];
}
-(void)setZoom:(NSNumber*) zoom {
self.session.videoZoomFactor = [zoom integerValue];
}
-(void)setCamera:(NSString*)camera{
if([camera isEqualToString:@"front"] || [camera isEqualToString:@"back"]){
if(![camera isEqualToString:_camera]){
_camera = camera;
[self.session toggleCamera];
}
}
}
- (void)streamingSessionSendingBufferDidFull:(id)session {
NSString *log = @"Buffer is full";
NSLog(@"%@", log);
}
- (void)streamingSession:(id)session sendingBufferDidDropItems:(NSArray *)items {
NSString *log = @"Frame dropped";
NSLog(@"%@", log);
}
- (void)stopSession {
dispatch_async(self.sessionQueue, ^{
[self.session stop];
});
}
- (void)startSession {
dispatch_async(self.sessionQueue, ^{
NSURL *streamURL = [NSURL URLWithString:self.rtmpURL];
[self.session startWithPushURL:streamURL feedback:^(PLStreamStartStateFeedback feedback) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"success ");
});
}];
});
}
- (void)cameraStreamingSession:(PLCameraStreamingSession *)session streamStatusDidUpdate:(PLStreamStatus *)status {
NSString *log = [NSString stringWithFormat:@"Stream Status: %@", status];
NSLog(@"%@", log);
}
- (void)cameraStreamingSession:(PLCameraStreamingSession *)session streamStateDidChange:(PLStreamState)state {
NSString *log = [NSString stringWithFormat:@"Stream State: %s", stateNames[state]];
NSLog(@"%@", log);
switch (state) {
case PLStreamStateUnknow:
[_eventDispatcher sendInputEventWithName:@"onLoading" body:@{@"target": self.reactTag}];
break;
case PLStreamStateConnecting:
[_eventDispatcher sendInputEventWithName:@"onConnecting" body:@{@"target": self.reactTag}];
break;
case PLStreamStateConnected:
[_eventDispatcher sendInputEventWithName:@"onStreaming" body:@{@"target": self.reactTag}];
break;
case PLStreamStateDisconnecting:
break;
case PLStreamStateDisconnected:
[_eventDispatcher sendInputEventWithName:@"onDisconnected" body:@{@"target": self.reactTag}];
[_eventDispatcher sendInputEventWithName:@"onShutdown" body:@{@"target": self.reactTag}]; //FIXME
break;
case PLStreamStateError:
[_eventDispatcher sendInputEventWithName:@"onIOError" body:@{@"target": self.reactTag}];
break;
default:
break;
}
}
- (void)cameraStreamingSession:(PLCameraStreamingSession *)session didDisconnectWithError:(NSError *)error {
NSString *log = [NSString stringWithFormat:@"Stream State: Error. %@", error];
NSLog(@"%@", log);
[self startSession];
}
- (void)reachabilityChanged:(NSNotification *)notif{
Reachability *curReach = [notif object];
NSParameterAssert([curReach isKindOfClass:[Reachability class]]);
NetworkStatus status = [curReach currentReachabilityStatus];
if (NotReachable == status) {
// 对断网情况做处理
[self stopSession];
}
NSString *log = [NSString stringWithFormat:@"Networkt Status: %s", networkStatus[status]];
NSLog(@"%@", log);
}
- (void)handleInterruption:(NSNotification *)notification {
if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification]) {
NSLog(@"Interruption notification");
if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeBegan]]) {
NSLog(@"InterruptionTypeBegan");
} else {
// the facetime iOS 9 has a bug: 1 does not send interrupt end 2 you can use application become active, and repeat set audio session acitve until success. ref http://blog.corywiles.com/broken-facetime-audio-interruptions-in-ios-9
NSLog(@"InterruptionTypeEnded");
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];
}
}
}
@end
================================================
FILE: ios/RCTPili/RCTPili/RCTStreamingManager.h
================================================
//
// RCTStreamingManager.h
// RCTPili
//
// Created by guguyanhua on 16/5/26.
// Copyright © 2016年 pili. All rights reserved.
//
#import "RCTViewManager.h"
@interface RCTStreamingManager : RCTViewManager
@end
================================================
FILE: ios/RCTPili/RCTPili/RCTStreamingManager.m
================================================
//
// RCTStreamingManager.m
// RCTPili
//
// Created by guguyanhua on 16/5/26.
// Copyright © 2016年 pili. All rights reserved.
//
#import "RCTStreamingManager.h"
#import "RCTStreaming.h"
@implementation RCTStreamingManager
RCT_EXPORT_MODULE();
@synthesize bridge = _bridge;
- (UIView *)view
{
return [[RCTStreaming alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
}
- (NSArray *)customDirectEventTypes
{
return @[
@"onReady",
@"onConnecting",
@"onStreaming",
@"onShutdown",
@"onIOError",
@"onDisconnected"
];
}
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
RCT_EXPORT_VIEW_PROPERTY(rtmpURL, NSString);
RCT_EXPORT_VIEW_PROPERTY(profile, NSDictionary);
RCT_EXPORT_VIEW_PROPERTY(started, BOOL);
RCT_EXPORT_VIEW_PROPERTY(muted, BOOL);
RCT_EXPORT_VIEW_PROPERTY(zoom, NSNumber);
RCT_EXPORT_VIEW_PROPERTY(focus, BOOL);
RCT_EXPORT_VIEW_PROPERTY(camera, NSString);
@end
================================================
FILE: ios/RCTPili/RCTPili/Reachability.h
================================================
/*
File: Reachability.h
Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
Version: 3.5
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
Inc. ("Apple") in consideration of your agreement to the following
terms, and your use, installation, modification or redistribution of
this Apple software constitutes acceptance of these terms. If you do
not agree with these terms, please do not use, install, modify or
redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and
subject to these terms, Apple grants you a personal, non-exclusive
license, under Apple's copyrights in this original Apple software (the
"Apple Software"), to use, reproduce, modify and redistribute the Apple
Software, with or without modifications, in source and/or binary forms;
provided that if you redistribute the Apple Software in its entirety and
without modifications, you must retain this notice and the following
text and disclaimers in all such redistributions of the Apple Software.
Neither the name, trademarks, service marks or logos of Apple Inc. may
be used to endorse or promote products derived from the Apple Software
without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or
implied, are granted by Apple herein, including but not limited to any
patent rights that may be infringed by your derivative works or by other
works in which the Apple Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Copyright (C) 2014 Apple Inc. All Rights Reserved.
*/
#import
#import
#import
typedef enum : NSInteger {
NotReachable = 0,
ReachableViaWiFi,
ReachableViaWWAN
} NetworkStatus;
extern NSString *kReachabilityChangedNotification;
@interface Reachability : NSObject
/*!
* Use to check the reachability of a given host name.
*/
+ (instancetype)reachabilityWithHostName:(NSString *)hostName;
/*!
* Use to check the reachability of a given IP address.
*/
+ (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress;
/*!
* Checks whether the default route is available. Should be used by applications that do not connect to a particular host.
*/
+ (instancetype)reachabilityForInternetConnection;
/*!
* Checks whether a local WiFi connection is available.
*/
+ (instancetype)reachabilityForLocalWiFi;
/*!
* Start listening for reachability notifications on the current run loop.
*/
- (BOOL)startNotifier;
- (void)stopNotifier;
- (NetworkStatus)currentReachabilityStatus;
/*!
* WWAN may be available, but not active until a connection has been established. WiFi may require a connection for VPN on Demand.
*/
- (BOOL)connectionRequired;
@end
================================================
FILE: ios/RCTPili/RCTPili/Reachability.m
================================================
/*
File: Reachability.m
Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
Version: 3.5
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
Inc. ("Apple") in consideration of your agreement to the following
terms, and your use, installation, modification or redistribution of
this Apple software constitutes acceptance of these terms. If you do
not agree with these terms, please do not use, install, modify or
redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and
subject to these terms, Apple grants you a personal, non-exclusive
license, under Apple's copyrights in this original Apple software (the
"Apple Software"), to use, reproduce, modify and redistribute the Apple
Software, with or without modifications, in source and/or binary forms;
provided that if you redistribute the Apple Software in its entirety and
without modifications, you must retain this notice and the following
text and disclaimers in all such redistributions of the Apple Software.
Neither the name, trademarks, service marks or logos of Apple Inc. may
be used to endorse or promote products derived from the Apple Software
without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or
implied, are granted by Apple herein, including but not limited to any
patent rights that may be infringed by your derivative works or by other
works in which the Apple Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Copyright (C) 2014 Apple Inc. All Rights Reserved.
*/
#import
#import
#import
#import
#import
#import "Reachability.h"
NSString *kReachabilityChangedNotification = @"kNetworkReachabilityChangedNotification";
#pragma mark - Supporting functions
#define kShouldPrintReachabilityFlags 0
static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
{
#if kShouldPrintReachabilityFlags
NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
(flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
(flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
(flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
(flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-',
comment
);
#endif
}
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
{
#pragma unused (target, flags)
NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
NSCAssert([(__bridge NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
Reachability* noteObject = (__bridge Reachability *)info;
// Post a notification to notify the client that the network reachability changed.
[[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
}
#pragma mark - Reachability implementation
@implementation Reachability
{
BOOL _alwaysReturnLocalWiFiStatus; //default is NO
SCNetworkReachabilityRef _reachabilityRef;
}
+ (instancetype)reachabilityWithHostName:(NSString *)hostName
{
Reachability* returnValue = NULL;
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
if (reachability != NULL)
{
returnValue= [[self alloc] init];
if (returnValue != NULL)
{
returnValue->_reachabilityRef = reachability;
returnValue->_alwaysReturnLocalWiFiStatus = NO;
}
}
return returnValue;
}
+ (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress
{
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)hostAddress);
Reachability* returnValue = NULL;
if (reachability != NULL)
{
returnValue = [[self alloc] init];
if (returnValue != NULL)
{
returnValue->_reachabilityRef = reachability;
returnValue->_alwaysReturnLocalWiFiStatus = NO;
}
}
return returnValue;
}
+ (instancetype)reachabilityForInternetConnection
{
struct sockaddr_in zeroAddress;
bzero(&zeroAddress, sizeof(zeroAddress));
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;
return [self reachabilityWithAddress:&zeroAddress];
}
+ (instancetype)reachabilityForLocalWiFi
{
struct sockaddr_in localWifiAddress;
bzero(&localWifiAddress, sizeof(localWifiAddress));
localWifiAddress.sin_len = sizeof(localWifiAddress);
localWifiAddress.sin_family = AF_INET;
// IN_LINKLOCALNETNUM is defined in as 169.254.0.0.
localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
Reachability* returnValue = [self reachabilityWithAddress: &localWifiAddress];
if (returnValue != NULL)
{
returnValue->_alwaysReturnLocalWiFiStatus = YES;
}
return returnValue;
}
#pragma mark - Start and stop notifier
- (BOOL)startNotifier
{
BOOL returnValue = NO;
SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context))
{
if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
{
returnValue = YES;
}
}
return returnValue;
}
- (void)stopNotifier
{
if (_reachabilityRef != NULL)
{
SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
}
- (void)dealloc
{
[self stopNotifier];
if (_reachabilityRef != NULL)
{
CFRelease(_reachabilityRef);
}
}
#pragma mark - Network Flag Handling
- (NetworkStatus)localWiFiStatusForFlags:(SCNetworkReachabilityFlags)flags
{
PrintReachabilityFlags(flags, "localWiFiStatusForFlags");
NetworkStatus returnValue = NotReachable;
if ((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect))
{
returnValue = ReachableViaWiFi;
}
return returnValue;
}
- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags
{
PrintReachabilityFlags(flags, "networkStatusForFlags");
if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
{
// The target host is not reachable.
return NotReachable;
}
NetworkStatus returnValue = NotReachable;
if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
{
/*
If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi...
*/
returnValue = ReachableViaWiFi;
}
if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
{
/*
... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs...
*/
if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
{
/*
... and no [user] intervention is needed...
*/
returnValue = ReachableViaWiFi;
}
}
if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
{
/*
... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
*/
returnValue = ReachableViaWWAN;
}
return returnValue;
}
- (BOOL)connectionRequired
{
NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
{
return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
}
return NO;
}
- (NetworkStatus)currentReachabilityStatus
{
NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL SCNetworkReachabilityRef");
NetworkStatus returnValue = NotReachable;
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
{
if (_alwaysReturnLocalWiFiStatus)
{
returnValue = [self localWiFiStatusForFlags:flags];
}
else
{
returnValue = [self networkStatusForFlags:flags];
}
}
return returnValue;
}
@end
================================================
FILE: ios/RCTPili/RCTPili.podspec
================================================
#
# Be sure to run `pod spec lint RCTPili.podspec' to ensure this is a
# valid spec and to remove all comments including this before submitting the spec.
#
# To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html
# To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
#
Pod::Spec.new do |s|
s.name = "RCTPili"
s.version = "2.0.0"
s.summary = "React Native Pili SDK Bridge"
# This description is used to generate tags and improve search results.
# * Think: What does it do? Why did you write it? What is the focus?
# * Try to keep it short, snappy and to the point.
# * Write the description between the DESC delimiters below.
# * Finally, don't worry about the indent, CocoaPods strips it!
s.description = <<-DESC
React Native Pili SDK Bridge
DESC
s.homepage = "http://www.airapps.cn/package/react-native-pili"
s.license = "MIT"
# s.license = { :type => "MIT", :file => "FILE_LICENSE" }
s.author = { "buhe" => "bugu1986@126.com" }
s.platform = :ios, "7.0"
s.source = { :git => "https://github.com/buhe/react-native-piliv2.git", :tag => "master" }
s.source_files = "RCTPili/**/*.{h,m}"
s.requires_arc = true
# s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
s.dependency "React"
s.dependency "PLMediaStreamingKit"
s.dependency "PLPlayerKit"
end
================================================
FILE: ios/RCTPili/RCTPili.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
78CFC6511D8942EC00386E6B /* RCTPili.h in Headers */ = {isa = PBXBuildFile; fileRef = 78CFC6451D8942EC00386E6B /* RCTPili.h */; };
78CFC6521D8942EC00386E6B /* RCTPili.m in Sources */ = {isa = PBXBuildFile; fileRef = 78CFC6461D8942EC00386E6B /* RCTPili.m */; };
78CFC6531D8942EC00386E6B /* RCTPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 78CFC6471D8942EC00386E6B /* RCTPlayer.h */; };
78CFC6541D8942EC00386E6B /* RCTPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 78CFC6481D8942EC00386E6B /* RCTPlayer.m */; };
78CFC6551D8942EC00386E6B /* RCTPlayerManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 78CFC6491D8942EC00386E6B /* RCTPlayerManager.h */; };
78CFC6561D8942EC00386E6B /* RCTPlayerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 78CFC64A1D8942EC00386E6B /* RCTPlayerManager.m */; };
78CFC6571D8942EC00386E6B /* RCTStreaming.h in Headers */ = {isa = PBXBuildFile; fileRef = 78CFC64B1D8942EC00386E6B /* RCTStreaming.h */; };
78CFC6581D8942EC00386E6B /* RCTStreaming.m in Sources */ = {isa = PBXBuildFile; fileRef = 78CFC64C1D8942EC00386E6B /* RCTStreaming.m */; };
78CFC6591D8942EC00386E6B /* RCTStreamingManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 78CFC64D1D8942EC00386E6B /* RCTStreamingManager.h */; };
78CFC65A1D8942EC00386E6B /* RCTStreamingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 78CFC64E1D8942EC00386E6B /* RCTStreamingManager.m */; };
78CFC65B1D8942EC00386E6B /* Reachability.h in Headers */ = {isa = PBXBuildFile; fileRef = 78CFC64F1D8942EC00386E6B /* Reachability.h */; };
78CFC65C1D8942EC00386E6B /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 78CFC6501D8942EC00386E6B /* Reachability.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
78CFC63A1D89426D00386E6B /* RCTPili.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RCTPili.framework; sourceTree = BUILT_PRODUCTS_DIR; };
78CFC63F1D89426D00386E6B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
78CFC6451D8942EC00386E6B /* RCTPili.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPili.h; sourceTree = ""; };
78CFC6461D8942EC00386E6B /* RCTPili.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPili.m; sourceTree = ""; };
78CFC6471D8942EC00386E6B /* RCTPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPlayer.h; sourceTree = ""; };
78CFC6481D8942EC00386E6B /* RCTPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPlayer.m; sourceTree = ""; };
78CFC6491D8942EC00386E6B /* RCTPlayerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPlayerManager.h; sourceTree = ""; };
78CFC64A1D8942EC00386E6B /* RCTPlayerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTPlayerManager.m; sourceTree = ""; };
78CFC64B1D8942EC00386E6B /* RCTStreaming.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTStreaming.h; sourceTree = ""; };
78CFC64C1D8942EC00386E6B /* RCTStreaming.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTStreaming.m; sourceTree = ""; };
78CFC64D1D8942EC00386E6B /* RCTStreamingManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTStreamingManager.h; sourceTree = ""; };
78CFC64E1D8942EC00386E6B /* RCTStreamingManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTStreamingManager.m; sourceTree = ""; };
78CFC64F1D8942EC00386E6B /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reachability.h; sourceTree = ""; };
78CFC6501D8942EC00386E6B /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
78CFC6361D89426D00386E6B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
78CFC6301D89426D00386E6B = {
isa = PBXGroup;
children = (
78CFC63C1D89426D00386E6B /* RCTPili */,
78CFC63B1D89426D00386E6B /* Products */,
);
sourceTree = "";
};
78CFC63B1D89426D00386E6B /* Products */ = {
isa = PBXGroup;
children = (
78CFC63A1D89426D00386E6B /* RCTPili.framework */,
);
name = Products;
sourceTree = "";
};
78CFC63C1D89426D00386E6B /* RCTPili */ = {
isa = PBXGroup;
children = (
78CFC6451D8942EC00386E6B /* RCTPili.h */,
78CFC6461D8942EC00386E6B /* RCTPili.m */,
78CFC6471D8942EC00386E6B /* RCTPlayer.h */,
78CFC6481D8942EC00386E6B /* RCTPlayer.m */,
78CFC6491D8942EC00386E6B /* RCTPlayerManager.h */,
78CFC64A1D8942EC00386E6B /* RCTPlayerManager.m */,
78CFC64B1D8942EC00386E6B /* RCTStreaming.h */,
78CFC64C1D8942EC00386E6B /* RCTStreaming.m */,
78CFC64D1D8942EC00386E6B /* RCTStreamingManager.h */,
78CFC64E1D8942EC00386E6B /* RCTStreamingManager.m */,
78CFC64F1D8942EC00386E6B /* Reachability.h */,
78CFC6501D8942EC00386E6B /* Reachability.m */,
78CFC63F1D89426D00386E6B /* Info.plist */,
);
path = RCTPili;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
78CFC6371D89426D00386E6B /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
78CFC6511D8942EC00386E6B /* RCTPili.h in Headers */,
78CFC6591D8942EC00386E6B /* RCTStreamingManager.h in Headers */,
78CFC6551D8942EC00386E6B /* RCTPlayerManager.h in Headers */,
78CFC65B1D8942EC00386E6B /* Reachability.h in Headers */,
78CFC6531D8942EC00386E6B /* RCTPlayer.h in Headers */,
78CFC6571D8942EC00386E6B /* RCTStreaming.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
78CFC6391D89426D00386E6B /* RCTPili */ = {
isa = PBXNativeTarget;
buildConfigurationList = 78CFC6421D89426D00386E6B /* Build configuration list for PBXNativeTarget "RCTPili" */;
buildPhases = (
78CFC6351D89426D00386E6B /* Sources */,
78CFC6361D89426D00386E6B /* Frameworks */,
78CFC6371D89426D00386E6B /* Headers */,
78CFC6381D89426D00386E6B /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = RCTPili;
productName = RCTPili;
productReference = 78CFC63A1D89426D00386E6B /* RCTPili.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
78CFC6311D89426D00386E6B /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0730;
ORGANIZATIONNAME = airapps;
TargetAttributes = {
78CFC6391D89426D00386E6B = {
CreatedOnToolsVersion = 7.3.1;
};
};
};
buildConfigurationList = 78CFC6341D89426D00386E6B /* Build configuration list for PBXProject "RCTPili" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 78CFC6301D89426D00386E6B;
productRefGroup = 78CFC63B1D89426D00386E6B /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
78CFC6391D89426D00386E6B /* RCTPili */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
78CFC6381D89426D00386E6B /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
78CFC6351D89426D00386E6B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
78CFC6581D8942EC00386E6B /* RCTStreaming.m in Sources */,
78CFC65A1D8942EC00386E6B /* RCTStreamingManager.m in Sources */,
78CFC6541D8942EC00386E6B /* RCTPlayer.m in Sources */,
78CFC6521D8942EC00386E6B /* RCTPili.m in Sources */,
78CFC65C1D8942EC00386E6B /* Reachability.m in Sources */,
78CFC6561D8942EC00386E6B /* RCTPlayerManager.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
78CFC6401D89426D00386E6B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
78CFC6411D89426D00386E6B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
78CFC6431D89426D00386E6B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"${PODS_ROOT}/Headers/Public/React\"",
);
INFOPLIST_FILE = RCTPili/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = cn.airapps.RCTPili;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Debug;
};
78CFC6441D89426D00386E6B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"${PODS_ROOT}/Headers/Public/React\"",
);
INFOPLIST_FILE = RCTPili/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = cn.airapps.RCTPili;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
78CFC6341D89426D00386E6B /* Build configuration list for PBXProject "RCTPili" */ = {
isa = XCConfigurationList;
buildConfigurations = (
78CFC6401D89426D00386E6B /* Debug */,
78CFC6411D89426D00386E6B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
78CFC6421D89426D00386E6B /* Build configuration list for PBXNativeTarget "RCTPili" */ = {
isa = XCConfigurationList;
buildConfigurations = (
78CFC6431D89426D00386E6B /* Debug */,
78CFC6441D89426D00386E6B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 78CFC6311D89426D00386E6B /* Project object */;
}
================================================
FILE: package.json
================================================
{
"name": "react-native-pili",
"version": "2.3.0",
"description": "Pili Streaming Cloud React Native SDK",
"main": "index.js",
"scripts": {
"test": "npm test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/buhe/react-native-pili.git"
},
"keywords": [
"React",
"Native",
"SDK",
"Qiniu",
"Pili",
"Stream",
"Cloud"
],
"author": "buhe",
"license": "MIT",
"bugs": {
"url": "https://github.com/buhe/react-native-pili/issues"
},
"homepage": "https://github.com/buhe/react-native-pili#readme",
"devDependencies": {
"react": "^0.14.8",
"react-native": "^0.24.1"
}
}